forked from luck/tmp_suning_uos_patched
drm/nouveau/i2c: balance port acquire/release
This was a half-finished hack before, just enough to handle the shared aux/i2c pad thing on G94 and up. We got lucky with locking etc up until now, as this was (generally) all protected by the DRM mode_config lock. It's about to become a lot more likely to hit the races. Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
This commit is contained in:
parent
0ff32977ea
commit
d2ae2eb469
@ -62,6 +62,8 @@ struct nouveau_i2c {
|
|||||||
|
|
||||||
struct nouveau_i2c_port *(*find)(struct nouveau_i2c *, u8 index);
|
struct nouveau_i2c_port *(*find)(struct nouveau_i2c *, u8 index);
|
||||||
struct nouveau_i2c_port *(*find_type)(struct nouveau_i2c *, u16 type);
|
struct nouveau_i2c_port *(*find_type)(struct nouveau_i2c *, u16 type);
|
||||||
|
int (*acquire)(struct nouveau_i2c_port *, unsigned long timeout);
|
||||||
|
void (*release)(struct nouveau_i2c_port *);
|
||||||
int (*identify)(struct nouveau_i2c *, int index,
|
int (*identify)(struct nouveau_i2c *, int index,
|
||||||
const char *what, struct nouveau_i2c_board_info *,
|
const char *what, struct nouveau_i2c_board_info *,
|
||||||
bool (*match)(struct nouveau_i2c_port *,
|
bool (*match)(struct nouveau_i2c_port *,
|
||||||
|
@ -27,10 +27,14 @@
|
|||||||
int
|
int
|
||||||
nv_rdaux(struct nouveau_i2c_port *port, u32 addr, u8 *data, u8 size)
|
nv_rdaux(struct nouveau_i2c_port *port, u32 addr, u8 *data, u8 size)
|
||||||
{
|
{
|
||||||
|
struct nouveau_i2c *i2c = nouveau_i2c(port);
|
||||||
if (port->func->aux) {
|
if (port->func->aux) {
|
||||||
if (port->func->acquire)
|
int ret = i2c->acquire(port, 0);
|
||||||
port->func->acquire(port);
|
if (ret == 0) {
|
||||||
return port->func->aux(port, true, 9, addr, data, size);
|
ret = port->func->aux(port, true, 9, addr, data, size);
|
||||||
|
i2c->release(port);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
}
|
}
|
||||||
@ -38,10 +42,14 @@ nv_rdaux(struct nouveau_i2c_port *port, u32 addr, u8 *data, u8 size)
|
|||||||
int
|
int
|
||||||
nv_wraux(struct nouveau_i2c_port *port, u32 addr, u8 *data, u8 size)
|
nv_wraux(struct nouveau_i2c_port *port, u32 addr, u8 *data, u8 size)
|
||||||
{
|
{
|
||||||
|
struct nouveau_i2c *i2c = nouveau_i2c(port);
|
||||||
if (port->func->aux) {
|
if (port->func->aux) {
|
||||||
if (port->func->acquire)
|
int ret = i2c->acquire(port, 0);
|
||||||
port->func->acquire(port);
|
if (ret == 0) {
|
||||||
return port->func->aux(port, true, 8, addr, data, size);
|
ret = port->func->aux(port, true, 8, addr, data, size);
|
||||||
|
i2c->release(port);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
}
|
}
|
||||||
@ -50,13 +58,16 @@ static int
|
|||||||
aux_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
|
aux_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
|
||||||
{
|
{
|
||||||
struct nouveau_i2c_port *port = adap->algo_data;
|
struct nouveau_i2c_port *port = adap->algo_data;
|
||||||
|
struct nouveau_i2c *i2c = nouveau_i2c(port);
|
||||||
struct i2c_msg *msg = msgs;
|
struct i2c_msg *msg = msgs;
|
||||||
int ret, mcnt = num;
|
int ret, mcnt = num;
|
||||||
|
|
||||||
if (!port->func->aux)
|
if (!port->func->aux)
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
if ( port->func->acquire)
|
|
||||||
port->func->acquire(port);
|
ret = i2c->acquire(port, 0);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
while (mcnt--) {
|
while (mcnt--) {
|
||||||
u8 remaining = msg->len;
|
u8 remaining = msg->len;
|
||||||
@ -75,8 +86,10 @@ aux_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
|
|||||||
cmd |= 4; /* MOT */
|
cmd |= 4; /* MOT */
|
||||||
|
|
||||||
ret = port->func->aux(port, true, cmd, msg->addr, ptr, cnt);
|
ret = port->func->aux(port, true, cmd, msg->addr, ptr, cnt);
|
||||||
if (ret < 0)
|
if (ret < 0) {
|
||||||
|
i2c->release(port);
|
||||||
return ret;
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
ptr += cnt;
|
ptr += cnt;
|
||||||
remaining -= cnt;
|
remaining -= cnt;
|
||||||
@ -85,6 +98,7 @@ aux_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
|
|||||||
msg++;
|
msg++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
i2c->release(port);
|
||||||
return num;
|
return num;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -47,9 +47,15 @@ nouveau_i2c_pre_xfer(struct i2c_adapter *adap)
|
|||||||
{
|
{
|
||||||
struct i2c_algo_bit_data *bit = adap->algo_data;
|
struct i2c_algo_bit_data *bit = adap->algo_data;
|
||||||
struct nouveau_i2c_port *port = bit->data;
|
struct nouveau_i2c_port *port = bit->data;
|
||||||
if (port->func->acquire)
|
return nouveau_i2c(port)->acquire(port, bit->timeout);
|
||||||
port->func->acquire(port);
|
}
|
||||||
return 0;
|
|
||||||
|
static void
|
||||||
|
nouveau_i2c_post_xfer(struct i2c_adapter *adap)
|
||||||
|
{
|
||||||
|
struct i2c_algo_bit_data *bit = adap->algo_data;
|
||||||
|
struct nouveau_i2c_port *port = bit->data;
|
||||||
|
return nouveau_i2c(port)->release(port);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -130,6 +136,7 @@ nouveau_i2c_port_create_(struct nouveau_object *parent,
|
|||||||
bit->timeout = usecs_to_jiffies(2200);
|
bit->timeout = usecs_to_jiffies(2200);
|
||||||
bit->data = port;
|
bit->data = port;
|
||||||
bit->pre_xfer = nouveau_i2c_pre_xfer;
|
bit->pre_xfer = nouveau_i2c_pre_xfer;
|
||||||
|
bit->post_xfer = nouveau_i2c_post_xfer;
|
||||||
bit->setsda = nouveau_i2c_setsda;
|
bit->setsda = nouveau_i2c_setsda;
|
||||||
bit->setscl = nouveau_i2c_setscl;
|
bit->setscl = nouveau_i2c_setscl;
|
||||||
bit->getsda = nouveau_i2c_getsda;
|
bit->getsda = nouveau_i2c_getsda;
|
||||||
@ -194,6 +201,21 @@ nouveau_i2c_find_type(struct nouveau_i2c *i2c, u16 type)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
nouveau_i2c_release(struct nouveau_i2c_port *port)
|
||||||
|
{
|
||||||
|
if (port->func->release)
|
||||||
|
port->func->release(port);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
nouveau_i2c_acquire(struct nouveau_i2c_port *port, unsigned long timeout)
|
||||||
|
{
|
||||||
|
if (port->func->acquire)
|
||||||
|
port->func->acquire(port);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
nouveau_i2c_identify(struct nouveau_i2c *i2c, int index, const char *what,
|
nouveau_i2c_identify(struct nouveau_i2c *i2c, int index, const char *what,
|
||||||
struct nouveau_i2c_board_info *info,
|
struct nouveau_i2c_board_info *info,
|
||||||
@ -383,6 +405,8 @@ nouveau_i2c_create_(struct nouveau_object *parent,
|
|||||||
nv_subdev(i2c)->intr = nouveau_i2c_intr;
|
nv_subdev(i2c)->intr = nouveau_i2c_intr;
|
||||||
i2c->find = nouveau_i2c_find;
|
i2c->find = nouveau_i2c_find;
|
||||||
i2c->find_type = nouveau_i2c_find_type;
|
i2c->find_type = nouveau_i2c_find_type;
|
||||||
|
i2c->acquire = nouveau_i2c_acquire;
|
||||||
|
i2c->release = nouveau_i2c_release;
|
||||||
i2c->identify = nouveau_i2c_identify;
|
i2c->identify = nouveau_i2c_identify;
|
||||||
INIT_LIST_HEAD(&i2c->ports);
|
INIT_LIST_HEAD(&i2c->ports);
|
||||||
|
|
||||||
|
@ -187,8 +187,9 @@ i2c_bit_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
|
|||||||
struct i2c_msg *msg = msgs;
|
struct i2c_msg *msg = msgs;
|
||||||
int ret = 0, mcnt = num;
|
int ret = 0, mcnt = num;
|
||||||
|
|
||||||
if (port->func->acquire)
|
ret = nouveau_i2c(port)->acquire(port, nsecs_to_jiffies(T_TIMEOUT));
|
||||||
port->func->acquire(port);
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
while (!ret && mcnt--) {
|
while (!ret && mcnt--) {
|
||||||
u8 remaining = msg->len;
|
u8 remaining = msg->len;
|
||||||
@ -210,6 +211,7 @@ i2c_bit_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
|
|||||||
}
|
}
|
||||||
|
|
||||||
i2c_stop(port);
|
i2c_stop(port);
|
||||||
|
nouveau_i2c(port)->release(port);
|
||||||
return (ret < 0) ? ret : num;
|
return (ret < 0) ? ret : num;
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
|
Loading…
Reference in New Issue
Block a user