From 0cc90d0504335fe0119cba51870ca3ba33781b8d Mon Sep 17 00:00:00 2001 From: gcc_2023 Date: Tue, 20 Jun 2023 18:45:40 +0800 Subject: [PATCH 1/3] test --- drivers/gpu/drm/nouveau/nvkm/subdev/i2c/aux.c | 212 ------------------ drivers/gpu/drm/nouveau/nvkm/subdev/i2c/aux.h | 39 ---- include/soc/arc/aux.h | 63 ------ 3 files changed, 314 deletions(-) delete mode 100644 drivers/gpu/drm/nouveau/nvkm/subdev/i2c/aux.c delete mode 100644 drivers/gpu/drm/nouveau/nvkm/subdev/i2c/aux.h delete mode 100644 include/soc/arc/aux.h diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/aux.c b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/aux.c deleted file mode 100644 index a11637b0f6cc..000000000000 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/aux.c +++ /dev/null @@ -1,212 +0,0 @@ -/* - * Copyright 2009 Red Hat Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR - * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - * - * Authors: Ben Skeggs - */ -#include "aux.h" -#include "pad.h" - -static int -nvkm_i2c_aux_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) -{ - struct nvkm_i2c_aux *aux = container_of(adap, typeof(*aux), i2c); - struct i2c_msg *msg = msgs; - int ret, mcnt = num; - - ret = nvkm_i2c_aux_acquire(aux); - if (ret) - return ret; - - while (mcnt--) { - u8 remaining = msg->len; - u8 *ptr = msg->buf; - - while (remaining) { - u8 cnt, retries, cmd; - - if (msg->flags & I2C_M_RD) - cmd = 1; - else - cmd = 0; - - if (mcnt || remaining > 16) - cmd |= 4; /* MOT */ - - for (retries = 0, cnt = 0; - retries < 32 && !cnt; - retries++) { - cnt = min_t(u8, remaining, 16); - ret = aux->func->xfer(aux, true, cmd, - msg->addr, ptr, &cnt); - if (ret < 0) - goto out; - } - if (!cnt) { - AUX_TRACE(aux, "no data after 32 retries"); - ret = -EIO; - goto out; - } - - ptr += cnt; - remaining -= cnt; - } - - msg++; - } - - ret = num; -out: - nvkm_i2c_aux_release(aux); - return ret; -} - -static u32 -nvkm_i2c_aux_i2c_func(struct i2c_adapter *adap) -{ - return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; -} - -static const struct i2c_algorithm -nvkm_i2c_aux_i2c_algo = { - .master_xfer = nvkm_i2c_aux_i2c_xfer, - .functionality = nvkm_i2c_aux_i2c_func -}; - -void -nvkm_i2c_aux_monitor(struct nvkm_i2c_aux *aux, bool monitor) -{ - struct nvkm_i2c_pad *pad = aux->pad; - AUX_TRACE(aux, "monitor: %s", monitor ? "yes" : "no"); - if (monitor) - nvkm_i2c_pad_mode(pad, NVKM_I2C_PAD_AUX); - else - nvkm_i2c_pad_mode(pad, NVKM_I2C_PAD_OFF); -} - -void -nvkm_i2c_aux_release(struct nvkm_i2c_aux *aux) -{ - struct nvkm_i2c_pad *pad = aux->pad; - AUX_TRACE(aux, "release"); - nvkm_i2c_pad_release(pad); - mutex_unlock(&aux->mutex); -} - -int -nvkm_i2c_aux_acquire(struct nvkm_i2c_aux *aux) -{ - struct nvkm_i2c_pad *pad = aux->pad; - int ret; - - AUX_TRACE(aux, "acquire"); - mutex_lock(&aux->mutex); - - if (aux->enabled) - ret = nvkm_i2c_pad_acquire(pad, NVKM_I2C_PAD_AUX); - else - ret = -EIO; - - if (ret) - mutex_unlock(&aux->mutex); - return ret; -} - -int -nvkm_i2c_aux_xfer(struct nvkm_i2c_aux *aux, bool retry, u8 type, - u32 addr, u8 *data, u8 *size) -{ - if (!*size && !aux->func->address_only) { - AUX_ERR(aux, "address-only transaction dropped"); - return -ENOSYS; - } - return aux->func->xfer(aux, retry, type, addr, data, size); -} - -int -nvkm_i2c_aux_lnk_ctl(struct nvkm_i2c_aux *aux, int nr, int bw, bool ef) -{ - if (aux->func->lnk_ctl) - return aux->func->lnk_ctl(aux, nr, bw, ef); - return -ENODEV; -} - -void -nvkm_i2c_aux_del(struct nvkm_i2c_aux **paux) -{ - struct nvkm_i2c_aux *aux = *paux; - if (aux && !WARN_ON(!aux->func)) { - AUX_TRACE(aux, "dtor"); - list_del(&aux->head); - i2c_del_adapter(&aux->i2c); - kfree(*paux); - *paux = NULL; - } -} - -void -nvkm_i2c_aux_init(struct nvkm_i2c_aux *aux) -{ - AUX_TRACE(aux, "init"); - mutex_lock(&aux->mutex); - aux->enabled = true; - mutex_unlock(&aux->mutex); -} - -void -nvkm_i2c_aux_fini(struct nvkm_i2c_aux *aux) -{ - AUX_TRACE(aux, "fini"); - mutex_lock(&aux->mutex); - aux->enabled = false; - mutex_unlock(&aux->mutex); -} - -int -nvkm_i2c_aux_ctor(const struct nvkm_i2c_aux_func *func, - struct nvkm_i2c_pad *pad, int id, - struct nvkm_i2c_aux *aux) -{ - struct nvkm_device *device = pad->i2c->subdev.device; - - aux->func = func; - aux->pad = pad; - aux->id = id; - mutex_init(&aux->mutex); - list_add_tail(&aux->head, &pad->i2c->aux); - AUX_TRACE(aux, "ctor"); - - snprintf(aux->i2c.name, sizeof(aux->i2c.name), "nvkm-%s-aux-%04x", - dev_name(device->dev), id); - aux->i2c.owner = THIS_MODULE; - aux->i2c.dev.parent = device->dev; - aux->i2c.algo = &nvkm_i2c_aux_i2c_algo; - return i2c_add_adapter(&aux->i2c); -} - -int -nvkm_i2c_aux_new_(const struct nvkm_i2c_aux_func *func, - struct nvkm_i2c_pad *pad, int id, - struct nvkm_i2c_aux **paux) -{ - if (!(*paux = kzalloc(sizeof(**paux), GFP_KERNEL))) - return -ENOMEM; - return nvkm_i2c_aux_ctor(func, pad, id, *paux); -} diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/aux.h b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/aux.h deleted file mode 100644 index 08f6b2ee64ab..000000000000 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/aux.h +++ /dev/null @@ -1,39 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -#ifndef __NVKM_I2C_AUX_H__ -#define __NVKM_I2C_AUX_H__ -#include "pad.h" - -struct nvkm_i2c_aux_func { - bool address_only; - int (*xfer)(struct nvkm_i2c_aux *, bool retry, u8 type, - u32 addr, u8 *data, u8 *size); - int (*lnk_ctl)(struct nvkm_i2c_aux *, int link_nr, int link_bw, - bool enhanced_framing); -}; - -int nvkm_i2c_aux_ctor(const struct nvkm_i2c_aux_func *, struct nvkm_i2c_pad *, - int id, struct nvkm_i2c_aux *); -int nvkm_i2c_aux_new_(const struct nvkm_i2c_aux_func *, struct nvkm_i2c_pad *, - int id, struct nvkm_i2c_aux **); -void nvkm_i2c_aux_del(struct nvkm_i2c_aux **); -void nvkm_i2c_aux_init(struct nvkm_i2c_aux *); -void nvkm_i2c_aux_fini(struct nvkm_i2c_aux *); -int nvkm_i2c_aux_xfer(struct nvkm_i2c_aux *, bool retry, u8 type, - u32 addr, u8 *data, u8 *size); - -int g94_i2c_aux_new_(const struct nvkm_i2c_aux_func *, struct nvkm_i2c_pad *, - int, u8, struct nvkm_i2c_aux **); - -int g94_i2c_aux_new(struct nvkm_i2c_pad *, int, u8, struct nvkm_i2c_aux **); -int g94_i2c_aux_xfer(struct nvkm_i2c_aux *, bool, u8, u32, u8 *, u8 *); -int gf119_i2c_aux_new(struct nvkm_i2c_pad *, int, u8, struct nvkm_i2c_aux **); -int gm200_i2c_aux_new(struct nvkm_i2c_pad *, int, u8, struct nvkm_i2c_aux **); - -#define AUX_MSG(b,l,f,a...) do { \ - struct nvkm_i2c_aux *_aux = (b); \ - nvkm_##l(&_aux->pad->i2c->subdev, "aux %04x: "f"\n", _aux->id, ##a); \ -} while(0) -#define AUX_ERR(b,f,a...) AUX_MSG((b), error, f, ##a) -#define AUX_DBG(b,f,a...) AUX_MSG((b), debug, f, ##a) -#define AUX_TRACE(b,f,a...) AUX_MSG((b), trace, f, ##a) -#endif diff --git a/include/soc/arc/aux.h b/include/soc/arc/aux.h deleted file mode 100644 index 8c3fb13e0452..000000000000 --- a/include/soc/arc/aux.h +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright (C) 2016-2017 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. - * - */ - -#ifndef __SOC_ARC_AUX_H__ -#define __SOC_ARC_AUX_H__ - -#ifdef CONFIG_ARC - -#define read_aux_reg(r) __builtin_arc_lr(r) - -/* gcc builtin sr needs reg param to be long immediate */ -#define write_aux_reg(r, v) __builtin_arc_sr((unsigned int)(v), r) - -#else /* !CONFIG_ARC */ - -static inline int read_aux_reg(u32 r) -{ - return 0; -} - -/* - * function helps elide unused variable warning - * see: http://lists.infradead.org/pipermail/linux-snps-arc/2016-November/001748.html - */ -static inline void write_aux_reg(u32 r, u32 v) -{ - ; -} - -#endif - -#define READ_BCR(reg, into) \ -{ \ - unsigned int tmp; \ - tmp = read_aux_reg(reg); \ - if (sizeof(tmp) == sizeof(into)) { \ - into = *((typeof(into) *)&tmp); \ - } else { \ - extern void bogus_undefined(void); \ - bogus_undefined(); \ - } \ -} - -#define WRITE_AUX(reg, into) \ -{ \ - unsigned int tmp; \ - if (sizeof(tmp) == sizeof(into)) { \ - tmp = (*(unsigned int *)&(into)); \ - write_aux_reg(reg, tmp); \ - } else { \ - extern void bogus_undefined(void); \ - bogus_undefined(); \ - } \ -} - - -#endif -- Gitee From e6ae6b161010cf3ccd373959b60a2fb16352da6a Mon Sep 17 00:00:00 2001 From: gcc_2023 Date: Tue, 20 Jun 2023 18:56:04 +0800 Subject: [PATCH 2/3] selinux: fix race condition when computing ocontext SIDs ANBZ: #5576 commit cbfcd13be5cb2a07868afe67520ed181956579a7 upstream. Signed-off-by: Ondrej Mosnacek Signed-off-by: Paul Moore --- security/selinux/ss/services.c | 159 ++++++++++++++++++--------------- 1 file changed, 87 insertions(+), 72 deletions(-) diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c index f3def298a90e..12763b6c7d51 100644 --- a/security/selinux/ss/services.c +++ b/security/selinux/ss/services.c @@ -2263,6 +2263,43 @@ size_t security_policydb_len(struct selinux_state *state) return len; } +/** + * ocontext_to_sid - Helper to safely get sid for an ocontext + * @sidtab: SID table + * @c: ocontext structure + * @index: index of the context entry (0 or 1) + * @out_sid: pointer to the resulting SID value + * + * For all ocontexts except OCON_ISID the SID fields are populated + * on-demand when needed. Since updating the SID value is an SMP-sensitive + * operation, this helper must be used to do that safely. + * + * WARNING: This function may return -ESTALE, indicating that the caller + * must retry the operation after re-acquiring the policy pointer! + */ +static int ocontext_to_sid(struct sidtab *sidtab, struct ocontext *c, + size_t index, u32 *out_sid) +{ + int rc; + u32 sid; + + /* Ensure the associated sidtab entry is visible to this thread. */ + sid = smp_load_acquire(&c->sid[index]); + if (!sid) { + rc = sidtab_context_to_sid(sidtab, &c->context[index], &sid); + if (rc) + return rc; + + /* + * Ensure the new sidtab entry is visible to other threads + * when they see the SID. + */ + smp_store_release(&c->sid[index], sid); + } + *out_sid = sid; + return 0; +} + /** * security_port_sid - Obtain the SID for a port. * @protocol: protocol number @@ -2275,10 +2312,12 @@ int security_port_sid(struct selinux_state *state, struct policydb *policydb; struct sidtab *sidtab; struct ocontext *c; - int rc = 0; + int rc; read_lock(&state->ss->policy_rwlock); +retry: + rc = 0; policydb = &state->ss->policydb; sidtab = &state->ss->sidtab; @@ -2292,14 +2331,11 @@ int security_port_sid(struct selinux_state *state, } if (c) { - if (!c->sid[0]) { - rc = sidtab_context_to_sid(sidtab, - &c->context[0], - &c->sid[0]); - if (rc) - goto out; - } - *out_sid = c->sid[0]; + rc = ocontext_to_sid(sidtab, c, 0, out_sid); + if (rc == -ESTALE) + goto retry; + if (rc) + goto out; } else { *out_sid = SECINITSID_PORT; } @@ -2321,10 +2357,12 @@ int security_ib_pkey_sid(struct selinux_state *state, struct policydb *policydb; struct sidtab *sidtab; struct ocontext *c; - int rc = 0; + int rc; read_lock(&state->ss->policy_rwlock); +retry: + rc = 0; policydb = &state->ss->policydb; sidtab = &state->ss->sidtab; @@ -2339,14 +2377,11 @@ int security_ib_pkey_sid(struct selinux_state *state, } if (c) { - if (!c->sid[0]) { - rc = sidtab_context_to_sid(sidtab, - &c->context[0], - &c->sid[0]); - if (rc) - goto out; - } - *out_sid = c->sid[0]; + rc = ocontext_to_sid(sidtab, c, 0, out_sid); + if (rc == -ESTALE) + goto retry; + if (rc) + goto out; } else *out_sid = SECINITSID_UNLABELED; @@ -2367,10 +2402,12 @@ int security_ib_endport_sid(struct selinux_state *state, struct policydb *policydb; struct sidtab *sidtab; struct ocontext *c; - int rc = 0; + int rc; read_lock(&state->ss->policy_rwlock); +retry: + rc = 0; policydb = &state->ss->policydb; sidtab = &state->ss->sidtab; @@ -2386,14 +2423,11 @@ int security_ib_endport_sid(struct selinux_state *state, } if (c) { - if (!c->sid[0]) { - rc = sidtab_context_to_sid(sidtab, - &c->context[0], - &c->sid[0]); - if (rc) - goto out; - } - *out_sid = c->sid[0]; + rc = ocontext_to_sid(sidtab, c, 0, out_sid); + if (rc == -ESTALE) + goto retry; + if (rc) + goto out; } else *out_sid = SECINITSID_UNLABELED; @@ -2412,11 +2446,13 @@ int security_netif_sid(struct selinux_state *state, { struct policydb *policydb; struct sidtab *sidtab; - int rc = 0; + int rc; struct ocontext *c; read_lock(&state->ss->policy_rwlock); +retry: + rc = 0; policydb = &state->ss->policydb; sidtab = &state->ss->sidtab; @@ -2428,19 +2464,11 @@ int security_netif_sid(struct selinux_state *state, } if (c) { - if (!c->sid[0] || !c->sid[1]) { - rc = sidtab_context_to_sid(sidtab, - &c->context[0], - &c->sid[0]); - if (rc) - goto out; - rc = sidtab_context_to_sid(sidtab, - &c->context[1], - &c->sid[1]); - if (rc) - goto out; - } - *if_sid = c->sid[0]; + rc = ocontext_to_sid(sidtab, c, 0, if_sid); + if (rc == -ESTALE) + goto retry; + if (rc) + goto out; } else *if_sid = SECINITSID_NETIF; @@ -2482,6 +2510,7 @@ int security_node_sid(struct selinux_state *state, read_lock(&state->ss->policy_rwlock); +retry: policydb = &state->ss->policydb; sidtab = &state->ss->sidtab; @@ -2524,14 +2553,11 @@ int security_node_sid(struct selinux_state *state, } if (c) { - if (!c->sid[0]) { - rc = sidtab_context_to_sid(sidtab, - &c->context[0], - &c->sid[0]); - if (rc) - goto out; - } - *out_sid = c->sid[0]; + rc = ocontext_to_sid(sidtab, c, 0, out_sid); + if (rc == -ESTALE) + goto retry; + if (rc) + goto out; } else { *out_sid = SECINITSID_NODE; } @@ -2690,7 +2716,7 @@ static inline int __security_genfs_sid(struct selinux_state *state, u16 sclass; struct genfs *genfs; struct ocontext *c; - int rc, cmp = 0; + int cmp = 0; while (path[0] == '/' && path[1] == '/') path++; @@ -2704,9 +2730,8 @@ static inline int __security_genfs_sid(struct selinux_state *state, break; } - rc = -ENOENT; if (!genfs || cmp) - goto out; + return -ENOENT; for (c = genfs->head; c; c = c->next) { len = strlen(c->u.name); @@ -2715,20 +2740,10 @@ static inline int __security_genfs_sid(struct selinux_state *state, break; } - rc = -ENOENT; if (!c) - goto out; - - if (!c->sid[0]) { - rc = sidtab_context_to_sid(sidtab, &c->context[0], &c->sid[0]); - if (rc) - goto out; - } + return -ENOENT; - *sid = c->sid[0]; - rc = 0; -out: - return rc; + return ocontext_to_sid(sidtab, c, 0, sid); } /** @@ -2763,13 +2778,15 @@ int security_fs_use(struct selinux_state *state, struct super_block *sb) { struct policydb *policydb; struct sidtab *sidtab; - int rc = 0; + int rc; struct ocontext *c; struct superblock_security_struct *sbsec = sb->s_security; const char *fstype = sb->s_type->name; read_lock(&state->ss->policy_rwlock); +retry: + rc = 0; policydb = &state->ss->policydb; sidtab = &state->ss->sidtab; @@ -2782,13 +2799,11 @@ int security_fs_use(struct selinux_state *state, struct super_block *sb) if (c) { sbsec->behavior = c->v.behavior; - if (!c->sid[0]) { - rc = sidtab_context_to_sid(sidtab, &c->context[0], - &c->sid[0]); - if (rc) - goto out; - } - sbsec->sid = c->sid[0]; + rc = ocontext_to_sid(sidtab, c, 0, &sbsec->sid); + if (rc == -ESTALE) + goto retry; + if (rc) + goto out; } else { rc = __security_genfs_sid(state, fstype, "/", SECCLASS_DIR, &sbsec->sid); -- Gitee From e51c338cbcf4f10b7bd80cec3e18d9a8216eccad Mon Sep 17 00:00:00 2001 From: gcc_2023 Date: Wed, 21 Jun 2023 02:26:39 +0000 Subject: [PATCH 3/3] Revert "test" This reverts commit 0cc90d0504335fe0119cba51870ca3ba33781b8d. --- drivers/gpu/drm/nouveau/nvkm/subdev/i2c/aux.c | 212 ++++++++++++++++++ drivers/gpu/drm/nouveau/nvkm/subdev/i2c/aux.h | 39 ++++ include/soc/arc/aux.h | 63 ++++++ 3 files changed, 314 insertions(+) create mode 100644 drivers/gpu/drm/nouveau/nvkm/subdev/i2c/aux.c create mode 100644 drivers/gpu/drm/nouveau/nvkm/subdev/i2c/aux.h create mode 100644 include/soc/arc/aux.h diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/aux.c b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/aux.c new file mode 100644 index 000000000000..a11637b0f6cc --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/aux.c @@ -0,0 +1,212 @@ +/* + * Copyright 2009 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Ben Skeggs + */ +#include "aux.h" +#include "pad.h" + +static int +nvkm_i2c_aux_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) +{ + struct nvkm_i2c_aux *aux = container_of(adap, typeof(*aux), i2c); + struct i2c_msg *msg = msgs; + int ret, mcnt = num; + + ret = nvkm_i2c_aux_acquire(aux); + if (ret) + return ret; + + while (mcnt--) { + u8 remaining = msg->len; + u8 *ptr = msg->buf; + + while (remaining) { + u8 cnt, retries, cmd; + + if (msg->flags & I2C_M_RD) + cmd = 1; + else + cmd = 0; + + if (mcnt || remaining > 16) + cmd |= 4; /* MOT */ + + for (retries = 0, cnt = 0; + retries < 32 && !cnt; + retries++) { + cnt = min_t(u8, remaining, 16); + ret = aux->func->xfer(aux, true, cmd, + msg->addr, ptr, &cnt); + if (ret < 0) + goto out; + } + if (!cnt) { + AUX_TRACE(aux, "no data after 32 retries"); + ret = -EIO; + goto out; + } + + ptr += cnt; + remaining -= cnt; + } + + msg++; + } + + ret = num; +out: + nvkm_i2c_aux_release(aux); + return ret; +} + +static u32 +nvkm_i2c_aux_i2c_func(struct i2c_adapter *adap) +{ + return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; +} + +static const struct i2c_algorithm +nvkm_i2c_aux_i2c_algo = { + .master_xfer = nvkm_i2c_aux_i2c_xfer, + .functionality = nvkm_i2c_aux_i2c_func +}; + +void +nvkm_i2c_aux_monitor(struct nvkm_i2c_aux *aux, bool monitor) +{ + struct nvkm_i2c_pad *pad = aux->pad; + AUX_TRACE(aux, "monitor: %s", monitor ? "yes" : "no"); + if (monitor) + nvkm_i2c_pad_mode(pad, NVKM_I2C_PAD_AUX); + else + nvkm_i2c_pad_mode(pad, NVKM_I2C_PAD_OFF); +} + +void +nvkm_i2c_aux_release(struct nvkm_i2c_aux *aux) +{ + struct nvkm_i2c_pad *pad = aux->pad; + AUX_TRACE(aux, "release"); + nvkm_i2c_pad_release(pad); + mutex_unlock(&aux->mutex); +} + +int +nvkm_i2c_aux_acquire(struct nvkm_i2c_aux *aux) +{ + struct nvkm_i2c_pad *pad = aux->pad; + int ret; + + AUX_TRACE(aux, "acquire"); + mutex_lock(&aux->mutex); + + if (aux->enabled) + ret = nvkm_i2c_pad_acquire(pad, NVKM_I2C_PAD_AUX); + else + ret = -EIO; + + if (ret) + mutex_unlock(&aux->mutex); + return ret; +} + +int +nvkm_i2c_aux_xfer(struct nvkm_i2c_aux *aux, bool retry, u8 type, + u32 addr, u8 *data, u8 *size) +{ + if (!*size && !aux->func->address_only) { + AUX_ERR(aux, "address-only transaction dropped"); + return -ENOSYS; + } + return aux->func->xfer(aux, retry, type, addr, data, size); +} + +int +nvkm_i2c_aux_lnk_ctl(struct nvkm_i2c_aux *aux, int nr, int bw, bool ef) +{ + if (aux->func->lnk_ctl) + return aux->func->lnk_ctl(aux, nr, bw, ef); + return -ENODEV; +} + +void +nvkm_i2c_aux_del(struct nvkm_i2c_aux **paux) +{ + struct nvkm_i2c_aux *aux = *paux; + if (aux && !WARN_ON(!aux->func)) { + AUX_TRACE(aux, "dtor"); + list_del(&aux->head); + i2c_del_adapter(&aux->i2c); + kfree(*paux); + *paux = NULL; + } +} + +void +nvkm_i2c_aux_init(struct nvkm_i2c_aux *aux) +{ + AUX_TRACE(aux, "init"); + mutex_lock(&aux->mutex); + aux->enabled = true; + mutex_unlock(&aux->mutex); +} + +void +nvkm_i2c_aux_fini(struct nvkm_i2c_aux *aux) +{ + AUX_TRACE(aux, "fini"); + mutex_lock(&aux->mutex); + aux->enabled = false; + mutex_unlock(&aux->mutex); +} + +int +nvkm_i2c_aux_ctor(const struct nvkm_i2c_aux_func *func, + struct nvkm_i2c_pad *pad, int id, + struct nvkm_i2c_aux *aux) +{ + struct nvkm_device *device = pad->i2c->subdev.device; + + aux->func = func; + aux->pad = pad; + aux->id = id; + mutex_init(&aux->mutex); + list_add_tail(&aux->head, &pad->i2c->aux); + AUX_TRACE(aux, "ctor"); + + snprintf(aux->i2c.name, sizeof(aux->i2c.name), "nvkm-%s-aux-%04x", + dev_name(device->dev), id); + aux->i2c.owner = THIS_MODULE; + aux->i2c.dev.parent = device->dev; + aux->i2c.algo = &nvkm_i2c_aux_i2c_algo; + return i2c_add_adapter(&aux->i2c); +} + +int +nvkm_i2c_aux_new_(const struct nvkm_i2c_aux_func *func, + struct nvkm_i2c_pad *pad, int id, + struct nvkm_i2c_aux **paux) +{ + if (!(*paux = kzalloc(sizeof(**paux), GFP_KERNEL))) + return -ENOMEM; + return nvkm_i2c_aux_ctor(func, pad, id, *paux); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/aux.h b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/aux.h new file mode 100644 index 000000000000..08f6b2ee64ab --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/aux.h @@ -0,0 +1,39 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef __NVKM_I2C_AUX_H__ +#define __NVKM_I2C_AUX_H__ +#include "pad.h" + +struct nvkm_i2c_aux_func { + bool address_only; + int (*xfer)(struct nvkm_i2c_aux *, bool retry, u8 type, + u32 addr, u8 *data, u8 *size); + int (*lnk_ctl)(struct nvkm_i2c_aux *, int link_nr, int link_bw, + bool enhanced_framing); +}; + +int nvkm_i2c_aux_ctor(const struct nvkm_i2c_aux_func *, struct nvkm_i2c_pad *, + int id, struct nvkm_i2c_aux *); +int nvkm_i2c_aux_new_(const struct nvkm_i2c_aux_func *, struct nvkm_i2c_pad *, + int id, struct nvkm_i2c_aux **); +void nvkm_i2c_aux_del(struct nvkm_i2c_aux **); +void nvkm_i2c_aux_init(struct nvkm_i2c_aux *); +void nvkm_i2c_aux_fini(struct nvkm_i2c_aux *); +int nvkm_i2c_aux_xfer(struct nvkm_i2c_aux *, bool retry, u8 type, + u32 addr, u8 *data, u8 *size); + +int g94_i2c_aux_new_(const struct nvkm_i2c_aux_func *, struct nvkm_i2c_pad *, + int, u8, struct nvkm_i2c_aux **); + +int g94_i2c_aux_new(struct nvkm_i2c_pad *, int, u8, struct nvkm_i2c_aux **); +int g94_i2c_aux_xfer(struct nvkm_i2c_aux *, bool, u8, u32, u8 *, u8 *); +int gf119_i2c_aux_new(struct nvkm_i2c_pad *, int, u8, struct nvkm_i2c_aux **); +int gm200_i2c_aux_new(struct nvkm_i2c_pad *, int, u8, struct nvkm_i2c_aux **); + +#define AUX_MSG(b,l,f,a...) do { \ + struct nvkm_i2c_aux *_aux = (b); \ + nvkm_##l(&_aux->pad->i2c->subdev, "aux %04x: "f"\n", _aux->id, ##a); \ +} while(0) +#define AUX_ERR(b,f,a...) AUX_MSG((b), error, f, ##a) +#define AUX_DBG(b,f,a...) AUX_MSG((b), debug, f, ##a) +#define AUX_TRACE(b,f,a...) AUX_MSG((b), trace, f, ##a) +#endif diff --git a/include/soc/arc/aux.h b/include/soc/arc/aux.h new file mode 100644 index 000000000000..8c3fb13e0452 --- /dev/null +++ b/include/soc/arc/aux.h @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2016-2017 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. + * + */ + +#ifndef __SOC_ARC_AUX_H__ +#define __SOC_ARC_AUX_H__ + +#ifdef CONFIG_ARC + +#define read_aux_reg(r) __builtin_arc_lr(r) + +/* gcc builtin sr needs reg param to be long immediate */ +#define write_aux_reg(r, v) __builtin_arc_sr((unsigned int)(v), r) + +#else /* !CONFIG_ARC */ + +static inline int read_aux_reg(u32 r) +{ + return 0; +} + +/* + * function helps elide unused variable warning + * see: http://lists.infradead.org/pipermail/linux-snps-arc/2016-November/001748.html + */ +static inline void write_aux_reg(u32 r, u32 v) +{ + ; +} + +#endif + +#define READ_BCR(reg, into) \ +{ \ + unsigned int tmp; \ + tmp = read_aux_reg(reg); \ + if (sizeof(tmp) == sizeof(into)) { \ + into = *((typeof(into) *)&tmp); \ + } else { \ + extern void bogus_undefined(void); \ + bogus_undefined(); \ + } \ +} + +#define WRITE_AUX(reg, into) \ +{ \ + unsigned int tmp; \ + if (sizeof(tmp) == sizeof(into)) { \ + tmp = (*(unsigned int *)&(into)); \ + write_aux_reg(reg, tmp); \ + } else { \ + extern void bogus_undefined(void); \ + bogus_undefined(); \ + } \ +} + + +#endif -- Gitee