diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-18 17:35:05 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-18 17:39:31 +0000 |
commit | 85c675d0d09a45a135bddd15d7b385f8758c32fb (patch) | |
tree | 76267dbc9b9a130337be3640948fe397b04ac629 /drivers/i3c | |
parent | Adding upstream version 6.6.15. (diff) | |
download | linux-85c675d0d09a45a135bddd15d7b385f8758c32fb.tar.xz linux-85c675d0d09a45a135bddd15d7b385f8758c32fb.zip |
Adding upstream version 6.7.7.upstream/6.7.7
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'drivers/i3c')
-rw-r--r-- | drivers/i3c/master.c | 55 | ||||
-rw-r--r-- | drivers/i3c/master/dw-i3c-master.c | 2 | ||||
-rw-r--r-- | drivers/i3c/master/i3c-master-cdns.c | 9 | ||||
-rw-r--r-- | drivers/i3c/master/mipi-i3c-hci/cmd_v1.c | 1 | ||||
-rw-r--r-- | drivers/i3c/master/mipi-i3c-hci/core.c | 14 | ||||
-rw-r--r-- | drivers/i3c/master/mipi-i3c-hci/dma.c | 19 | ||||
-rw-r--r-- | drivers/i3c/master/svc-i3c-master.c | 6 |
7 files changed, 83 insertions, 23 deletions
diff --git a/drivers/i3c/master.c b/drivers/i3c/master.c index 0e9ff5500a..95caa16270 100644 --- a/drivers/i3c/master.c +++ b/drivers/i3c/master.c @@ -22,6 +22,7 @@ static DEFINE_IDR(i3c_bus_idr); static DEFINE_MUTEX(i3c_core_lock); static int __i3c_first_dynamic_bus_num; +static BLOCKING_NOTIFIER_HEAD(i3c_bus_notifier); /** * i3c_bus_maintenance_lock - Lock the bus for a maintenance operation @@ -453,6 +454,36 @@ static int i3c_bus_init(struct i3c_bus *i3cbus, struct device_node *np) return 0; } +void i3c_for_each_bus_locked(int (*fn)(struct i3c_bus *bus, void *data), + void *data) +{ + struct i3c_bus *bus; + int id; + + mutex_lock(&i3c_core_lock); + idr_for_each_entry(&i3c_bus_idr, bus, id) + fn(bus, data); + mutex_unlock(&i3c_core_lock); +} +EXPORT_SYMBOL_GPL(i3c_for_each_bus_locked); + +int i3c_register_notifier(struct notifier_block *nb) +{ + return blocking_notifier_chain_register(&i3c_bus_notifier, nb); +} +EXPORT_SYMBOL_GPL(i3c_register_notifier); + +int i3c_unregister_notifier(struct notifier_block *nb) +{ + return blocking_notifier_chain_unregister(&i3c_bus_notifier, nb); +} +EXPORT_SYMBOL_GPL(i3c_unregister_notifier); + +static void i3c_bus_notify(struct i3c_bus *bus, unsigned int action) +{ + blocking_notifier_call_chain(&i3c_bus_notifier, action, bus); +} + static const char * const i3c_bus_mode_strings[] = { [I3C_BUS_MODE_PURE] = "pure", [I3C_BUS_MODE_MIXED_FAST] = "mixed-fast", @@ -2311,7 +2342,7 @@ static int i3c_master_i2c_adapter_init(struct i3c_master_controller *master) adap->dev.parent = master->dev.parent; adap->owner = master->dev.parent->driver->owner; adap->algo = &i3c_master_i2c_algo; - strncpy(adap->name, dev_name(master->dev.parent), sizeof(adap->name)); + strscpy(adap->name, dev_name(master->dev.parent), sizeof(adap->name)); /* FIXME: Should we allow i3c masters to override these values? */ adap->timeout = 1000; @@ -2374,7 +2405,7 @@ static void i3c_master_unregister_i3c_devs(struct i3c_master_controller *master) void i3c_master_queue_ibi(struct i3c_dev_desc *dev, struct i3c_ibi_slot *slot) { atomic_inc(&dev->ibi->pending_ibis); - queue_work(dev->common.master->wq, &slot->work); + queue_work(dev->ibi->wq, &slot->work); } EXPORT_SYMBOL_GPL(i3c_master_queue_ibi); @@ -2631,6 +2662,10 @@ int i3c_master_register(struct i3c_master_controller *master, device_initialize(&master->dev); dev_set_name(&master->dev, "i3c-%d", i3cbus->id); + master->dev.dma_mask = parent->dma_mask; + master->dev.coherent_dma_mask = parent->coherent_dma_mask; + master->dev.dma_parms = parent->dma_parms; + ret = of_populate_i3c_bus(master); if (ret) goto err_put_dev; @@ -2684,6 +2719,8 @@ int i3c_master_register(struct i3c_master_controller *master, if (ret) goto err_del_dev; + i3c_bus_notify(i3cbus, I3C_NOTIFY_BUS_ADD); + /* * We're done initializing the bus and the controller, we can now * register I3C devices discovered during the initial DAA. @@ -2716,6 +2753,8 @@ EXPORT_SYMBOL_GPL(i3c_master_register); */ void i3c_master_unregister(struct i3c_master_controller *master) { + i3c_bus_notify(&master->bus, I3C_NOTIFY_BUS_REMOVE); + i3c_master_i2c_adapter_cleanup(master); i3c_master_unregister_i3c_devs(master); i3c_master_bus_cleanup(master); @@ -2815,6 +2854,12 @@ int i3c_dev_request_ibi_locked(struct i3c_dev_desc *dev, if (!ibi) return -ENOMEM; + ibi->wq = alloc_ordered_workqueue(dev_name(i3cdev_to_dev(dev->dev)), WQ_MEM_RECLAIM); + if (!ibi->wq) { + kfree(ibi); + return -ENOMEM; + } + atomic_set(&ibi->pending_ibis, 0); init_completion(&ibi->all_ibis_handled); ibi->handler = req->handler; @@ -2842,6 +2887,12 @@ void i3c_dev_free_ibi_locked(struct i3c_dev_desc *dev) WARN_ON(i3c_dev_disable_ibi_locked(dev)); master->ops->free_ibi(dev); + + if (dev->ibi->wq) { + destroy_workqueue(dev->ibi->wq); + dev->ibi->wq = NULL; + } + kfree(dev->ibi); dev->ibi = NULL; } diff --git a/drivers/i3c/master/dw-i3c-master.c b/drivers/i3c/master/dw-i3c-master.c index 9332ae5f64..ef5751e91c 100644 --- a/drivers/i3c/master/dw-i3c-master.c +++ b/drivers/i3c/master/dw-i3c-master.c @@ -233,7 +233,7 @@ struct dw_i3c_xfer { struct completion comp; int ret; unsigned int ncmds; - struct dw_i3c_cmd cmds[]; + struct dw_i3c_cmd cmds[] __counted_by(ncmds); }; struct dw_i3c_i2c_dev_data { diff --git a/drivers/i3c/master/i3c-master-cdns.c b/drivers/i3c/master/i3c-master-cdns.c index 8f1fda3c7a..c1627f3552 100644 --- a/drivers/i3c/master/i3c-master-cdns.c +++ b/drivers/i3c/master/i3c-master-cdns.c @@ -76,7 +76,8 @@ #define PRESCL_CTRL0 0x14 #define PRESCL_CTRL0_I2C(x) ((x) << 16) #define PRESCL_CTRL0_I3C(x) (x) -#define PRESCL_CTRL0_MAX GENMASK(9, 0) +#define PRESCL_CTRL0_I3C_MAX GENMASK(9, 0) +#define PRESCL_CTRL0_I2C_MAX GENMASK(15, 0) #define PRESCL_CTRL1 0x18 #define PRESCL_CTRL1_PP_LOW_MASK GENMASK(15, 8) @@ -387,7 +388,7 @@ struct cdns_i3c_xfer { struct completion comp; int ret; unsigned int ncmds; - struct cdns_i3c_cmd cmds[]; + struct cdns_i3c_cmd cmds[] __counted_by(ncmds); }; struct cdns_i3c_data { @@ -1233,7 +1234,7 @@ static int cdns_i3c_master_bus_init(struct i3c_master_controller *m) return -EINVAL; pres = DIV_ROUND_UP(sysclk_rate, (bus->scl_rate.i3c * 4)) - 1; - if (pres > PRESCL_CTRL0_MAX) + if (pres > PRESCL_CTRL0_I3C_MAX) return -ERANGE; 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) max_i2cfreq = bus->scl_rate.i2c; pres = (sysclk_rate / (max_i2cfreq * 5)) - 1; - if (pres > PRESCL_CTRL0_MAX) + if (pres > PRESCL_CTRL0_I2C_MAX) return -ERANGE; bus->scl_rate.i2c = sysclk_rate / ((pres + 1) * 5); diff --git a/drivers/i3c/master/mipi-i3c-hci/cmd_v1.c b/drivers/i3c/master/mipi-i3c-hci/cmd_v1.c index 6a781f89b0..2b2323aa67 100644 --- a/drivers/i3c/master/mipi-i3c-hci/cmd_v1.c +++ b/drivers/i3c/master/mipi-i3c-hci/cmd_v1.c @@ -332,6 +332,7 @@ static int hci_cmd_v1_daa(struct i3c_hci *hci) CMD_A0_DEV_COUNT(1) | CMD_A0_ROC | CMD_A0_TOC; xfer->cmd_desc[1] = 0; + xfer->completion = &done; hci->io->queue_xfer(hci, xfer, 1); if (!wait_for_completion_timeout(&done, HZ) && hci->io->dequeue_xfer(hci, xfer, 1)) { diff --git a/drivers/i3c/master/mipi-i3c-hci/core.c b/drivers/i3c/master/mipi-i3c-hci/core.c index 837af83c85..1ae56a5699 100644 --- a/drivers/i3c/master/mipi-i3c-hci/core.c +++ b/drivers/i3c/master/mipi-i3c-hci/core.c @@ -161,10 +161,12 @@ static int i3c_hci_bus_init(struct i3c_master_controller *m) static void i3c_hci_bus_cleanup(struct i3c_master_controller *m) { struct i3c_hci *hci = to_i3c_hci(m); + struct platform_device *pdev = to_platform_device(m->dev.parent); DBG(""); reg_clear(HC_CONTROL, HC_CONTROL_BUS_ENABLE); + synchronize_irq(platform_get_irq(pdev, 0)); hci->io->cleanup(hci); if (hci->cmd == &mipi_i3c_hci_cmd_v1) mipi_i3c_hci_dat_v1.cleanup(hci); @@ -172,8 +174,7 @@ static void i3c_hci_bus_cleanup(struct i3c_master_controller *m) void mipi_i3c_hci_resume(struct i3c_hci *hci) { - /* the HC_CONTROL_RESUME bit is R/W1C so just read and write back */ - reg_write(HC_CONTROL, reg_read(HC_CONTROL)); + reg_set(HC_CONTROL, HC_CONTROL_RESUME); } /* located here rather than pio.c because needed bits are in core reg space */ @@ -610,17 +611,17 @@ static int i3c_hci_init(struct i3c_hci *hci) offset = FIELD_GET(DAT_TABLE_OFFSET, regval); hci->DAT_regs = offset ? hci->base_regs + offset : NULL; hci->DAT_entries = FIELD_GET(DAT_TABLE_SIZE, regval); - hci->DAT_entry_size = FIELD_GET(DAT_ENTRY_SIZE, regval); + hci->DAT_entry_size = FIELD_GET(DAT_ENTRY_SIZE, regval) ? 0 : 8; dev_info(&hci->master.dev, "DAT: %u %u-bytes entries at offset %#x\n", - hci->DAT_entries, hci->DAT_entry_size * 4, offset); + hci->DAT_entries, hci->DAT_entry_size, offset); regval = reg_read(DCT_SECTION); offset = FIELD_GET(DCT_TABLE_OFFSET, regval); hci->DCT_regs = offset ? hci->base_regs + offset : NULL; hci->DCT_entries = FIELD_GET(DCT_TABLE_SIZE, regval); - hci->DCT_entry_size = FIELD_GET(DCT_ENTRY_SIZE, regval); + hci->DCT_entry_size = FIELD_GET(DCT_ENTRY_SIZE, regval) ? 0 : 16; dev_info(&hci->master.dev, "DCT: %u %u-bytes entries at offset %#x\n", - hci->DCT_entries, hci->DCT_entry_size * 4, offset); + hci->DCT_entries, hci->DCT_entry_size, offset); regval = reg_read(RING_HEADERS_SECTION); offset = FIELD_GET(RING_HEADERS_OFFSET, regval); @@ -787,6 +788,7 @@ static struct platform_driver i3c_hci_driver = { }, }; module_platform_driver(i3c_hci_driver); +MODULE_ALIAS("platform:mipi-i3c-hci"); MODULE_AUTHOR("Nicolas Pitre <npitre@baylibre.com>"); MODULE_DESCRIPTION("MIPI I3C HCI driver"); diff --git a/drivers/i3c/master/mipi-i3c-hci/dma.c b/drivers/i3c/master/mipi-i3c-hci/dma.c index 71b5dbe45c..c805a84973 100644 --- a/drivers/i3c/master/mipi-i3c-hci/dma.c +++ b/drivers/i3c/master/mipi-i3c-hci/dma.c @@ -139,7 +139,7 @@ struct hci_rh_data { struct hci_rings_data { unsigned int total; - struct hci_rh_data headers[]; + struct hci_rh_data headers[] __counted_by(total); }; struct hci_dma_dev_ibi_data { @@ -229,6 +229,9 @@ static int hci_dma_init(struct i3c_hci *hci) hci->io_data = rings; rings->total = nr_rings; + regval = FIELD_PREP(MAX_HEADER_COUNT, rings->total); + rhs_reg_write(CONTROL, regval); + for (i = 0; i < rings->total; i++) { u32 offset = rhs_reg_read(RHn_OFFSET(i)); @@ -325,11 +328,10 @@ static int hci_dma_init(struct i3c_hci *hci) rh_reg_write(INTR_SIGNAL_ENABLE, regval); ring_ready: - rh_reg_write(RING_CONTROL, RING_CTRL_ENABLE); + rh_reg_write(RING_CONTROL, RING_CTRL_ENABLE | + RING_CTRL_RUN_STOP); } - regval = FIELD_PREP(MAX_HEADER_COUNT, rings->total); - rhs_reg_write(CONTROL, regval); return 0; err_out: @@ -345,6 +347,8 @@ static void hci_dma_unmap_xfer(struct i3c_hci *hci, for (i = 0; i < n; i++) { xfer = xfer_list + i; + if (!xfer->data) + continue; dma_unmap_single(&hci->master.dev, xfer->data_dma, xfer->data_len, xfer->rnw ? DMA_FROM_DEVICE : DMA_TO_DEVICE); @@ -450,10 +454,9 @@ static bool hci_dma_dequeue_xfer(struct i3c_hci *hci, /* * We're deep in it if ever this condition is ever met. * Hardware might still be writing to memory, etc. - * Better suspend the world than risking silent corruption. */ dev_crit(&hci->master.dev, "unable to abort the ring\n"); - BUG(); + WARN_ON(1); } for (i = 0; i < n; i++) { @@ -756,9 +759,11 @@ static bool hci_dma_irq_handler(struct i3c_hci *hci, unsigned int mask) if (status & INTR_RING_OP) complete(&rh->op_done); - if (status & INTR_TRANSFER_ABORT) + if (status & INTR_TRANSFER_ABORT) { dev_notice_ratelimited(&hci->master.dev, "ring %d: Transfer Aborted\n", i); + mipi_i3c_hci_resume(hci); + } if (status & INTR_WARN_INS_STOP_MODE) dev_warn_ratelimited(&hci->master.dev, "ring %d: Inserted Stop on Mode Change\n", i); diff --git a/drivers/i3c/master/svc-i3c-master.c b/drivers/i3c/master/svc-i3c-master.c index c395e52294..cf703c00f6 100644 --- a/drivers/i3c/master/svc-i3c-master.c +++ b/drivers/i3c/master/svc-i3c-master.c @@ -144,7 +144,7 @@ struct svc_i3c_xfer { int ret; unsigned int type; unsigned int ncmds; - struct svc_i3c_cmd cmds[]; + struct svc_i3c_cmd cmds[] __counted_by(ncmds); }; struct svc_i3c_regs_save { @@ -787,7 +787,7 @@ static int svc_i3c_master_do_daa_locked(struct svc_i3c_master *master, u8 data[6]; /* - * We only care about the 48-bit provisional ID yet to + * We only care about the 48-bit provisioned ID yet to * be sure a device does not nack an address twice. * Otherwise, we would just need to flush the RX FIFO. */ @@ -1703,7 +1703,7 @@ static const struct dev_pm_ops svc_i3c_pm_ops = { }; static const struct of_device_id svc_i3c_master_of_match_tbl[] = { - { .compatible = "silvaco,i3c-master" }, + { .compatible = "silvaco,i3c-master-v1"}, { /* sentinel */ }, }; MODULE_DEVICE_TABLE(of, svc_i3c_master_of_match_tbl); |