Commit 842c2953 authored by Ben Skeggs's avatar Ben Skeggs
Browse files

drm/nouveau/i2c: properly hand aux reply back to caller, and only retry on defer



Signed-off-by: default avatarBen Skeggs <bskeggs@redhat.com>
parent febb8449
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -33,7 +33,7 @@ struct nouveau_i2c_func {
	int  (*sense_scl)(struct nouveau_i2c_port *);
	int  (*sense_sda)(struct nouveau_i2c_port *);

	int  (*aux)(struct nouveau_i2c_port *, u8, u32, u8 *, u8);
	int  (*aux)(struct nouveau_i2c_port *, bool, u8, u32, u8 *, u8);
	int  (*pattern)(struct nouveau_i2c_port *, int pattern);
	int  (*lnk_ctl)(struct nouveau_i2c_port *, int nr, int bw, bool enh);
	int  (*drv_ctl)(struct nouveau_i2c_port *, int lane, int sw, int pe);
+2 −1
Original line number Diff line number Diff line
@@ -60,7 +60,8 @@ anx9805_train(struct nouveau_i2c_port *port, int link_nr, int link_bw, bool enh)
}

static int
anx9805_aux(struct nouveau_i2c_port *port, u8 type, u32 addr, u8 *data, u8 size)
anx9805_aux(struct nouveau_i2c_port *port, bool retry,
	    u8 type, u32 addr, u8 *data, u8 size)
{
	struct anx9805_i2c_port *chan = (void *)port;
	struct nouveau_i2c_port *mast = (void *)nv_object(chan)->parent;
+3 −3
Original line number Diff line number Diff line
@@ -30,7 +30,7 @@ nv_rdaux(struct nouveau_i2c_port *port, u32 addr, u8 *data, u8 size)
	if (port->func->aux) {
		if (port->func->acquire)
			port->func->acquire(port);
		return port->func->aux(port, 9, addr, data, size);
		return port->func->aux(port, true, 9, addr, data, size);
	}
	return -ENODEV;
}
@@ -41,7 +41,7 @@ nv_wraux(struct nouveau_i2c_port *port, u32 addr, u8 *data, u8 size)
	if (port->func->aux) {
		if (port->func->acquire)
			port->func->acquire(port);
		return port->func->aux(port, 8, addr, data, size);
		return port->func->aux(port, true, 8, addr, data, size);
	}
	return -ENODEV;
}
@@ -74,7 +74,7 @@ aux_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
			if (mcnt || remaining > 16)
				cmd |= 4; /* MOT */

			ret = port->func->aux(port, cmd, msg->addr, ptr, cnt);
			ret = port->func->aux(port, true, cmd, msg->addr, ptr, cnt);
			if (ret < 0)
				return ret;

+14 −9
Original line number Diff line number Diff line
@@ -69,7 +69,8 @@ auxch_init(struct nouveau_i2c *aux, int ch)
}

int
nv94_aux(struct nouveau_i2c_port *base, u8 type, u32 addr, u8 *data, u8 size)
nv94_aux(struct nouveau_i2c_port *base, bool retry,
	 u8 type, u32 addr, u8 *data, u8 size)
{
	struct nouveau_i2c *aux = nouveau_i2c(base);
	struct nv50_i2c_port *port = (void *)base;
@@ -105,9 +106,8 @@ nv94_aux(struct nouveau_i2c_port *base, u8 type, u32 addr, u8 *data, u8 size)
	ctrl |= size - 1;
	nv_wr32(aux, 0x00e4e0 + (ch * 0x50), addr);

	/* retry transaction a number of times on failure... */
	ret = -EREMOTEIO;
	for (retries = 0; retries < 32; retries++) {
	/* (maybe) retry transaction a number of times on failure... */
	for (retries = 0; !ret && retries < 32; retries++) {
		/* reset, and delay a while if this is a retry */
		nv_wr32(aux, 0x00e4e4 + (ch * 0x50), 0x80000000 | ctrl);
		nv_wr32(aux, 0x00e4e4 + (ch * 0x50), 0x00000000 | ctrl);
@@ -123,16 +123,21 @@ nv94_aux(struct nouveau_i2c_port *base, u8 type, u32 addr, u8 *data, u8 size)
			udelay(1);
			if (!timeout--) {
				AUX_ERR("tx req timeout 0x%08x\n", ctrl);
				ret = -EIO;
				goto out;
			}
		} while (ctrl & 0x00010000);
		ret = 1;

		/* read status, and check if transaction completed ok */
		stat = nv_mask(aux, 0x00e4e8 + (ch * 0x50), 0, 0);
		if (!(stat & 0x000f0f00)) {
			ret = 0;
			break;
		}
		if ((stat & 0x000f0000) == 0x00080000 ||
		    (stat & 0x000f0000) == 0x00020000)
			ret = retry ? 0 : 1;
		if ((stat & 0x00000100))
			ret = -ETIMEDOUT;
		if ((stat & 0x00000e00))
			ret = -EIO;

		AUX_DBG("%02d 0x%08x 0x%08x\n", retries, ctrl, stat);
	}
@@ -147,7 +152,7 @@ nv94_aux(struct nouveau_i2c_port *base, u8 type, u32 addr, u8 *data, u8 size)

out:
	auxch_fini(aux, ch);
	return ret;
	return ret < 0 ? ret : (stat & 0x000f0000) >> 16;
}

void