Skip to content

Commit a3f4a07

Browse files
committed
Merge tag 'i3c/for-6.8' of git://git.kernel.org/pub/scm/linux/kernel/git/i3c/linux
Pull i3c updates from Alexandre Belloni: "We are continuing to see more fixes as hardware is available and code is actually getting tested. Core: - Add a sysfs control for hotjoin - Add fallback method for GETMXDS CCC Drivers: - cdns: fix prescale for i2c clock - mipi-i3c-hci: more fixes now that the driver is used - svc: hotjoin enabling/disabling support" * tag 'i3c/for-6.8' of git://git.kernel.org/pub/scm/linux/kernel/git/i3c/linux: i3c: document hotjoin sysfs entry i3c: master: fix kernel-doc check warning i3c: master: cdns: Update maximum prescaler value for i2c clock i3c: master: fix Excess kernel-doc description warning i3c: master: svc: return actual transfer data len i3c: master: svc: rename read_len as actual_len i3c: add actual_len in i3c_priv_xfer i3c: master: svc: add hot join support i3c: master: add enable(disable) hot join in sys entry i3c: master: Fix build error i3c: Add fallback method for GETMXDS CCC i3c: mipi-i3c-hci: Add DMA bounce buffer for private transfers i3c: mipi-i3c-hci: Handle I3C address header error in hci_cmd_v1_daa() i3c: mipi-i3c-hci: Do not overallocate transfers in hci_cmd_v1_daa() i3c: mipi-i3c-hci: Report NACK response from CCC command to core
2 parents ed6c23b + 4fa0888 commit a3f4a07

File tree

10 files changed

+256
-28
lines changed

10 files changed

+256
-28
lines changed

Documentation/ABI/testing/sysfs-bus-i3c

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,21 @@ Description:
8888
This entry describes the HDRCAP of the master controller
8989
driving the bus.
9090

91+
What: /sys/bus/i3c/devices/i3c-<bus-id>/hotjoin
92+
KernelVersion: 6.8
93+
Contact: linux-i3c@vger.kernel.org
94+
Description:
95+
I3C’s Hot-Join mechanism allows an I3C Device to inform the
96+
Active Controller that a newly-joined Target is present on the
97+
I3C Bus and is ready to receive a Dynamic Address, in order to
98+
become fully functional on the Bus. Hot-Join is used when the
99+
Target is mounted on the same I3C bus and remains depowered
100+
until needed or until the Target is physically inserted into the
101+
I3C bus
102+
103+
This entry allows to enable or disable Hot-join of the Current
104+
Controller driving the bus.
105+
91106
What: /sys/bus/i3c/devices/i3c-<bus-id>/<bus-id>-<device-pid>
92107
KernelVersion: 5.0
93108
Contact: linux-i3c@vger.kernel.org

drivers/i3c/master.c

Lines changed: 93 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -557,6 +557,88 @@ static ssize_t i2c_scl_frequency_show(struct device *dev,
557557
}
558558
static DEVICE_ATTR_RO(i2c_scl_frequency);
559559

560+
static int i3c_set_hotjoin(struct i3c_master_controller *master, bool enable)
561+
{
562+
int ret;
563+
564+
if (!master || !master->ops)
565+
return -EINVAL;
566+
567+
if (!master->ops->enable_hotjoin || !master->ops->disable_hotjoin)
568+
return -EINVAL;
569+
570+
i3c_bus_normaluse_lock(&master->bus);
571+
572+
if (enable)
573+
ret = master->ops->enable_hotjoin(master);
574+
else
575+
ret = master->ops->disable_hotjoin(master);
576+
577+
master->hotjoin = enable;
578+
579+
i3c_bus_normaluse_unlock(&master->bus);
580+
581+
return ret;
582+
}
583+
584+
static ssize_t hotjoin_store(struct device *dev, struct device_attribute *attr,
585+
const char *buf, size_t count)
586+
{
587+
struct i3c_bus *i3cbus = dev_to_i3cbus(dev);
588+
int ret;
589+
bool res;
590+
591+
if (!i3cbus->cur_master)
592+
return -EINVAL;
593+
594+
if (kstrtobool(buf, &res))
595+
return -EINVAL;
596+
597+
ret = i3c_set_hotjoin(i3cbus->cur_master->common.master, res);
598+
if (ret)
599+
return ret;
600+
601+
return count;
602+
}
603+
604+
/*
605+
* i3c_master_enable_hotjoin - Enable hotjoin
606+
* @master: I3C master object
607+
*
608+
* Return: a 0 in case of success, an negative error code otherwise.
609+
*/
610+
int i3c_master_enable_hotjoin(struct i3c_master_controller *master)
611+
{
612+
return i3c_set_hotjoin(master, true);
613+
}
614+
EXPORT_SYMBOL_GPL(i3c_master_enable_hotjoin);
615+
616+
/*
617+
* i3c_master_disable_hotjoin - Disable hotjoin
618+
* @master: I3C master object
619+
*
620+
* Return: a 0 in case of success, an negative error code otherwise.
621+
*/
622+
int i3c_master_disable_hotjoin(struct i3c_master_controller *master)
623+
{
624+
return i3c_set_hotjoin(master, false);
625+
}
626+
EXPORT_SYMBOL_GPL(i3c_master_disable_hotjoin);
627+
628+
static ssize_t hotjoin_show(struct device *dev, struct device_attribute *da, char *buf)
629+
{
630+
struct i3c_bus *i3cbus = dev_to_i3cbus(dev);
631+
ssize_t ret;
632+
633+
i3c_bus_normaluse_lock(i3cbus);
634+
ret = sysfs_emit(buf, "%d\n", i3cbus->cur_master->common.master->hotjoin);
635+
i3c_bus_normaluse_unlock(i3cbus);
636+
637+
return ret;
638+
}
639+
640+
static DEVICE_ATTR_RW(hotjoin);
641+
560642
static struct attribute *i3c_masterdev_attrs[] = {
561643
&dev_attr_mode.attr,
562644
&dev_attr_current_master.attr,
@@ -567,6 +649,7 @@ static struct attribute *i3c_masterdev_attrs[] = {
567649
&dev_attr_pid.attr,
568650
&dev_attr_dynamic_address.attr,
569651
&dev_attr_hdrcap.attr,
652+
&dev_attr_hotjoin.attr,
570653
NULL,
571654
};
572655
ATTRIBUTE_GROUPS(i3c_masterdev);
@@ -1130,8 +1213,16 @@ static int i3c_master_getmxds_locked(struct i3c_master_controller *master,
11301213

11311214
i3c_ccc_cmd_init(&cmd, true, I3C_CCC_GETMXDS, &dest, 1);
11321215
ret = i3c_master_send_ccc_cmd_locked(master, &cmd);
1133-
if (ret)
1134-
goto out;
1216+
if (ret) {
1217+
/*
1218+
* Retry when the device does not support max read turnaround
1219+
* while expecting shorter length from this CCC command.
1220+
*/
1221+
dest.payload.len -= 3;
1222+
ret = i3c_master_send_ccc_cmd_locked(master, &cmd);
1223+
if (ret)
1224+
goto out;
1225+
}
11351226

11361227
if (dest.payload.len != 2 && dest.payload.len != 5) {
11371228
ret = -EIO;

drivers/i3c/master/i3c-master-cdns.c

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,8 @@
7676
#define PRESCL_CTRL0 0x14
7777
#define PRESCL_CTRL0_I2C(x) ((x) << 16)
7878
#define PRESCL_CTRL0_I3C(x) (x)
79-
#define PRESCL_CTRL0_MAX GENMASK(9, 0)
79+
#define PRESCL_CTRL0_I3C_MAX GENMASK(9, 0)
80+
#define PRESCL_CTRL0_I2C_MAX GENMASK(15, 0)
8081

8182
#define PRESCL_CTRL1 0x18
8283
#define PRESCL_CTRL1_PP_LOW_MASK GENMASK(15, 8)
@@ -1233,7 +1234,7 @@ static int cdns_i3c_master_bus_init(struct i3c_master_controller *m)
12331234
return -EINVAL;
12341235

12351236
pres = DIV_ROUND_UP(sysclk_rate, (bus->scl_rate.i3c * 4)) - 1;
1236-
if (pres > PRESCL_CTRL0_MAX)
1237+
if (pres > PRESCL_CTRL0_I3C_MAX)
12371238
return -ERANGE;
12381239

12391240
bus->scl_rate.i3c = sysclk_rate / ((pres + 1) * 4);
@@ -1246,7 +1247,7 @@ static int cdns_i3c_master_bus_init(struct i3c_master_controller *m)
12461247
max_i2cfreq = bus->scl_rate.i2c;
12471248

12481249
pres = (sysclk_rate / (max_i2cfreq * 5)) - 1;
1249-
if (pres > PRESCL_CTRL0_MAX)
1250+
if (pres > PRESCL_CTRL0_I2C_MAX)
12501251
return -ERANGE;
12511252

12521253
bus->scl_rate.i2c = sysclk_rate / ((pres + 1) * 5);

drivers/i3c/master/mipi-i3c-hci/cmd_v1.c

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -298,7 +298,7 @@ static int hci_cmd_v1_daa(struct i3c_hci *hci)
298298
unsigned int dcr, bcr;
299299
DECLARE_COMPLETION_ONSTACK(done);
300300

301-
xfer = hci_alloc_xfer(2);
301+
xfer = hci_alloc_xfer(1);
302302
if (!xfer)
303303
return -ENOMEM;
304304

@@ -339,12 +339,13 @@ static int hci_cmd_v1_daa(struct i3c_hci *hci)
339339
ret = -ETIME;
340340
break;
341341
}
342-
if (RESP_STATUS(xfer[0].response) == RESP_ERR_NACK &&
342+
if ((RESP_STATUS(xfer->response) == RESP_ERR_ADDR_HEADER ||
343+
RESP_STATUS(xfer->response) == RESP_ERR_NACK) &&
343344
RESP_DATA_LENGTH(xfer->response) == 1) {
344345
ret = 0; /* no more devices to be assigned */
345346
break;
346347
}
347-
if (RESP_STATUS(xfer[0].response) != RESP_SUCCESS) {
348+
if (RESP_STATUS(xfer->response) != RESP_SUCCESS) {
348349
ret = -EIO;
349350
break;
350351
}

drivers/i3c/master/mipi-i3c-hci/core.c

Lines changed: 48 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -245,7 +245,14 @@ static int i3c_hci_send_ccc_cmd(struct i3c_master_controller *m,
245245
if (ccc->rnw)
246246
ccc->dests[i - prefixed].payload.len =
247247
RESP_DATA_LENGTH(xfer[i].response);
248-
if (RESP_STATUS(xfer[i].response) != RESP_SUCCESS) {
248+
switch (RESP_STATUS(xfer[i].response)) {
249+
case RESP_SUCCESS:
250+
continue;
251+
case RESP_ERR_ADDR_HEADER:
252+
case RESP_ERR_NACK:
253+
ccc->err = I3C_ERROR_M2;
254+
fallthrough;
255+
default:
249256
ret = -EIO;
250257
goto out;
251258
}
@@ -269,6 +276,34 @@ static int i3c_hci_daa(struct i3c_master_controller *m)
269276
return hci->cmd->perform_daa(hci);
270277
}
271278

279+
static int i3c_hci_alloc_safe_xfer_buf(struct i3c_hci *hci,
280+
struct hci_xfer *xfer)
281+
{
282+
if (hci->io != &mipi_i3c_hci_dma ||
283+
xfer->data == NULL || !is_vmalloc_addr(xfer->data))
284+
return 0;
285+
286+
if (xfer->rnw)
287+
xfer->bounce_buf = kzalloc(xfer->data_len, GFP_KERNEL);
288+
else
289+
xfer->bounce_buf = kmemdup(xfer->data,
290+
xfer->data_len, GFP_KERNEL);
291+
292+
return xfer->bounce_buf == NULL ? -ENOMEM : 0;
293+
}
294+
295+
static void i3c_hci_free_safe_xfer_buf(struct i3c_hci *hci,
296+
struct hci_xfer *xfer)
297+
{
298+
if (hci->io != &mipi_i3c_hci_dma || xfer->bounce_buf == NULL)
299+
return;
300+
301+
if (xfer->rnw)
302+
memcpy(xfer->data, xfer->bounce_buf, xfer->data_len);
303+
304+
kfree(xfer->bounce_buf);
305+
}
306+
272307
static int i3c_hci_priv_xfers(struct i3c_dev_desc *dev,
273308
struct i3c_priv_xfer *i3c_xfers,
274309
int nxfers)
@@ -302,6 +337,9 @@ static int i3c_hci_priv_xfers(struct i3c_dev_desc *dev,
302337
}
303338
hci->cmd->prep_i3c_xfer(hci, dev, &xfer[i]);
304339
xfer[i].cmd_desc[0] |= CMD_0_ROC;
340+
ret = i3c_hci_alloc_safe_xfer_buf(hci, &xfer[i]);
341+
if (ret)
342+
goto out;
305343
}
306344
last = i - 1;
307345
xfer[last].cmd_desc[0] |= CMD_0_TOC;
@@ -325,6 +363,9 @@ static int i3c_hci_priv_xfers(struct i3c_dev_desc *dev,
325363
}
326364

327365
out:
366+
for (i = 0; i < nxfers; i++)
367+
i3c_hci_free_safe_xfer_buf(hci, &xfer[i]);
368+
328369
hci_free_xfer(xfer, nxfers);
329370
return ret;
330371
}
@@ -350,6 +391,9 @@ static int i3c_hci_i2c_xfers(struct i2c_dev_desc *dev,
350391
xfer[i].rnw = i2c_xfers[i].flags & I2C_M_RD;
351392
hci->cmd->prep_i2c_xfer(hci, dev, &xfer[i]);
352393
xfer[i].cmd_desc[0] |= CMD_0_ROC;
394+
ret = i3c_hci_alloc_safe_xfer_buf(hci, &xfer[i]);
395+
if (ret)
396+
goto out;
353397
}
354398
last = i - 1;
355399
xfer[last].cmd_desc[0] |= CMD_0_TOC;
@@ -371,6 +415,9 @@ static int i3c_hci_i2c_xfers(struct i2c_dev_desc *dev,
371415
}
372416

373417
out:
418+
for (i = 0; i < nxfers; i++)
419+
i3c_hci_free_safe_xfer_buf(hci, &xfer[i]);
420+
374421
hci_free_xfer(xfer, nxfers);
375422
return ret;
376423
}

drivers/i3c/master/mipi-i3c-hci/dma.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -362,6 +362,7 @@ static int hci_dma_queue_xfer(struct i3c_hci *hci,
362362
struct hci_rh_data *rh;
363363
unsigned int i, ring, enqueue_ptr;
364364
u32 op1_val, op2_val;
365+
void *buf;
365366

366367
/* For now we only use ring 0 */
367368
ring = 0;
@@ -390,9 +391,10 @@ static int hci_dma_queue_xfer(struct i3c_hci *hci,
390391

391392
/* 2nd and 3rd words of Data Buffer Descriptor Structure */
392393
if (xfer->data) {
394+
buf = xfer->bounce_buf ? xfer->bounce_buf : xfer->data;
393395
xfer->data_dma =
394396
dma_map_single(&hci->master.dev,
395-
xfer->data,
397+
buf,
396398
xfer->data_len,
397399
xfer->rnw ?
398400
DMA_FROM_DEVICE :

drivers/i3c/master/mipi-i3c-hci/hci.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@ struct hci_xfer {
9090
struct {
9191
/* DMA specific */
9292
dma_addr_t data_dma;
93+
void *bounce_buf;
9394
int ring_number;
9495
int ring_entry;
9596
};

0 commit comments

Comments
 (0)