Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge tag 'i3c/for-6.10' of git://git.kernel.org/pub/scm/linux/kernel/git/i3c/linux

Pull i3c updates from Alexandre Belloni:
"Runtime PM (power management) is improved and hot-join support has
been added to the dw controller driver.

Core:
- Allow device driver to trigger controller runtime PM

Drivers:
- dw: hot-join support
- svc: better IBI handling"

* tag 'i3c/for-6.10' of git://git.kernel.org/pub/scm/linux/kernel/git/i3c/linux:
i3c: dw: Add hot-join support.
i3c: master: Enable runtime PM for master controller
i3c: master: svc: fix invalidate IBI type and miss call client IBI handler
i3c: master: svc: change ENXIO to EAGAIN when IBI occurs during start frame
i3c: Add comment for -EAGAIN in i3c_device_do_priv_xfers()

+79 -16
+4
drivers/i3c/device.c
··· 27 27 * This function can sleep and thus cannot be called in atomic context. 28 28 * 29 29 * Return: 0 in case of success, a negative error core otherwise. 30 + * -EAGAIN: controller lost address arbitration. Target 31 + * (IBI, HJ or controller role request) win the bus. Client 32 + * driver needs to resend the 'xfers' some time later. 33 + * See I3C spec ver 1.1.1 09-Jun-2021. Section: 5.1.2.2.3. 30 34 */ 31 35 int i3c_device_do_priv_xfers(struct i3c_device *dev, 32 36 struct i3c_priv_xfer *xfers,
+6
drivers/i3c/master.c
··· 13 13 #include <linux/kernel.h> 14 14 #include <linux/list.h> 15 15 #include <linux/of.h> 16 + #include <linux/pm_runtime.h> 16 17 #include <linux/slab.h> 17 18 #include <linux/spinlock.h> 18 19 #include <linux/workqueue.h> ··· 2813 2812 2814 2813 i3c_bus_notify(i3cbus, I3C_NOTIFY_BUS_ADD); 2815 2814 2815 + pm_runtime_no_callbacks(&master->dev); 2816 + pm_suspend_ignore_children(&master->dev, true); 2817 + pm_runtime_enable(&master->dev); 2818 + 2816 2819 /* 2817 2820 * We're done initializing the bus and the controller, we can now 2818 2821 * register I3C devices discovered during the initial DAA. ··· 2854 2849 i3c_master_i2c_adapter_cleanup(master); 2855 2850 i3c_master_unregister_i3c_devs(master); 2856 2851 i3c_master_bus_cleanup(master); 2852 + pm_runtime_disable(&master->dev); 2857 2853 device_unregister(&master->dev); 2858 2854 } 2859 2855 EXPORT_SYMBOL_GPL(i3c_master_unregister);
+53 -12
drivers/i3c/master/dw-i3c-master.c
··· 1136 1136 data->ibi_pool = NULL; 1137 1137 } 1138 1138 1139 + static void dw_i3c_master_enable_sir_signal(struct dw_i3c_master *master, bool enable) 1140 + { 1141 + u32 reg; 1142 + 1143 + reg = readl(master->regs + INTR_STATUS_EN); 1144 + reg &= ~INTR_IBI_THLD_STAT; 1145 + if (enable) 1146 + reg |= INTR_IBI_THLD_STAT; 1147 + writel(reg, master->regs + INTR_STATUS_EN); 1148 + 1149 + reg = readl(master->regs + INTR_SIGNAL_EN); 1150 + reg &= ~INTR_IBI_THLD_STAT; 1151 + if (enable) 1152 + reg |= INTR_IBI_THLD_STAT; 1153 + writel(reg, master->regs + INTR_SIGNAL_EN); 1154 + } 1155 + 1139 1156 static void dw_i3c_master_set_sir_enabled(struct dw_i3c_master *master, 1140 1157 struct i3c_dev_desc *dev, 1141 1158 u8 idx, bool enable) ··· 1187 1170 } 1188 1171 writel(reg, master->regs + IBI_SIR_REQ_REJECT); 1189 1172 1190 - if (global) { 1191 - reg = readl(master->regs + INTR_STATUS_EN); 1192 - reg &= ~INTR_IBI_THLD_STAT; 1193 - if (enable) 1194 - reg |= INTR_IBI_THLD_STAT; 1195 - writel(reg, master->regs + INTR_STATUS_EN); 1173 + if (global) 1174 + dw_i3c_master_enable_sir_signal(master, enable); 1196 1175 1197 - reg = readl(master->regs + INTR_SIGNAL_EN); 1198 - reg &= ~INTR_IBI_THLD_STAT; 1199 - if (enable) 1200 - reg |= INTR_IBI_THLD_STAT; 1201 - writel(reg, master->regs + INTR_SIGNAL_EN); 1202 - } 1203 1176 1204 1177 spin_unlock_irqrestore(&master->devs_lock, flags); 1178 + } 1179 + 1180 + static int dw_i3c_master_enable_hotjoin(struct i3c_master_controller *m) 1181 + { 1182 + struct dw_i3c_master *master = to_dw_i3c_master(m); 1183 + 1184 + dw_i3c_master_enable_sir_signal(master, true); 1185 + writel(readl(master->regs + DEVICE_CTRL) & ~DEV_CTRL_HOT_JOIN_NACK, 1186 + master->regs + DEVICE_CTRL); 1187 + 1188 + return 0; 1189 + } 1190 + 1191 + static int dw_i3c_master_disable_hotjoin(struct i3c_master_controller *m) 1192 + { 1193 + struct dw_i3c_master *master = to_dw_i3c_master(m); 1194 + 1195 + writel(readl(master->regs + DEVICE_CTRL) | DEV_CTRL_HOT_JOIN_NACK, 1196 + master->regs + DEVICE_CTRL); 1197 + 1198 + return 0; 1205 1199 } 1206 1200 1207 1201 static int dw_i3c_master_enable_ibi(struct i3c_dev_desc *dev) ··· 1354 1326 1355 1327 if (IBI_TYPE_SIRQ(reg)) { 1356 1328 dw_i3c_master_handle_ibi_sir(master, reg); 1329 + } else if (IBI_TYPE_HJ(reg)) { 1330 + queue_work(master->base.wq, &master->hj_work); 1357 1331 } else { 1358 1332 len = IBI_QUEUE_STATUS_DATA_LEN(reg); 1359 1333 dev_info(&master->base.dev, ··· 1423 1393 .enable_ibi = dw_i3c_master_enable_ibi, 1424 1394 .disable_ibi = dw_i3c_master_disable_ibi, 1425 1395 .recycle_ibi_slot = dw_i3c_master_recycle_ibi_slot, 1396 + .enable_hotjoin = dw_i3c_master_enable_hotjoin, 1397 + .disable_hotjoin = dw_i3c_master_disable_hotjoin, 1426 1398 }; 1427 1399 1428 1400 /* default platform ops implementations */ ··· 1443 1411 .init = dw_i3c_platform_init_nop, 1444 1412 .set_dat_ibi = dw_i3c_platform_set_dat_ibi_nop, 1445 1413 }; 1414 + 1415 + static void dw_i3c_hj_work(struct work_struct *work) 1416 + { 1417 + struct dw_i3c_master *master = 1418 + container_of(work, typeof(*master), hj_work); 1419 + 1420 + i3c_master_do_daa(&master->base); 1421 + } 1446 1422 1447 1423 int dw_i3c_common_probe(struct dw_i3c_master *master, 1448 1424 struct platform_device *pdev) ··· 1509 1469 if (master->ibi_capable) 1510 1470 ops = &dw_mipi_i3c_ibi_ops; 1511 1471 1472 + INIT_WORK(&master->hj_work, dw_i3c_hj_work); 1512 1473 ret = i3c_master_register(&master->base, &pdev->dev, ops, false); 1513 1474 if (ret) 1514 1475 goto err_assert_rst;
+2
drivers/i3c/master/dw-i3c-master.h
··· 57 57 58 58 /* platform-specific data */ 59 59 const struct dw_i3c_platform_ops *platform_ops; 60 + 61 + struct work_struct hj_work; 60 62 }; 61 63 62 64 struct dw_i3c_platform_ops {
+14 -4
drivers/i3c/master/svc-i3c-master.c
··· 415 415 int ret; 416 416 417 417 mutex_lock(&master->lock); 418 + /* 419 + * IBIWON may be set before SVC_I3C_MCTRL_REQUEST_AUTO_IBI, causing 420 + * readl_relaxed_poll_timeout() to return immediately. Consequently, 421 + * ibitype will be 0 since it was last updated only after the 8th SCL 422 + * cycle, leading to missed client IBI handlers. 423 + * 424 + * A typical scenario is when IBIWON occurs and bus arbitration is lost 425 + * at svc_i3c_master_priv_xfers(). 426 + * 427 + * Clear SVC_I3C_MINT_IBIWON before sending SVC_I3C_MCTRL_REQUEST_AUTO_IBI. 428 + */ 429 + writel(SVC_I3C_MINT_IBIWON, master->regs + SVC_I3C_MSTATUS); 430 + 418 431 /* Acknowledge the incoming interrupt with the AUTOIBI mechanism */ 419 432 writel(SVC_I3C_MCTRL_REQUEST_AUTO_IBI | 420 433 SVC_I3C_MCTRL_IBIRESP_AUTO, ··· 441 428 svc_i3c_master_emit_stop(master); 442 429 goto reenable_ibis; 443 430 } 444 - 445 - /* Clear the interrupt status */ 446 - writel(SVC_I3C_MINT_IBIWON, master->regs + SVC_I3C_MSTATUS); 447 431 448 432 status = readl(master->regs + SVC_I3C_MSTATUS); 449 433 ibitype = SVC_I3C_MSTATUS_IBITYPE(status); ··· 1090 1080 * and yield the above events handler. 1091 1081 */ 1092 1082 if (SVC_I3C_MSTATUS_IBIWON(reg)) { 1093 - ret = -ENXIO; 1083 + ret = -EAGAIN; 1094 1084 *actual_len = 0; 1095 1085 goto emit_stop; 1096 1086 }