]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
soundwire: bus: Add internal slave ID and use for IRQs
authorCharles Keepax <ckeepax@opensource.cirrus.com>
Tue, 29 Apr 2025 10:18:08 +0000 (11:18 +0100)
committerVinod Koul <vkoul@kernel.org>
Wed, 14 May 2025 11:42:50 +0000 (12:42 +0100)
Currently the SoundWire IRQ code uses the dev_num to create an IRQ
mapping for each slave. However, there is an issue there, the dev_num
is only allocated when the slave enumerates on the bus and enumeration
may happen before or after probe of the slave driver. In the case
enumeration happens after probe of the slave driver then the IRQ
mapping will use dev_num before it is set. This could cause multiple
slaves to use zero as their IRQ mapping.

It is very desirable to have the IRQ mapped before the slave probe
is called, so drivers can do resource allocation in probe as normal. To
solve these issues add an internal ID created for each slave when it is
probed and use that for mapping the IRQ.

Signed-off-by: Charles Keepax <ckeepax@opensource.cirrus.com>
Reviewed-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.dev>
Link: https://lore.kernel.org/r/20250429101808.348462-3-ckeepax@opensource.cirrus.com
Signed-off-by: Vinod Koul <vkoul@kernel.org>
drivers/soundwire/bus.c
drivers/soundwire/bus_type.c
drivers/soundwire/irq.c
include/linux/soundwire/sdw.h

index 6cfec4a2af33a372886a3a92b2da254580f98943..377ab21c9cf0fba31e77e6c9ba65a3d3a46632aa 100644 (file)
@@ -56,6 +56,8 @@ int sdw_bus_master_add(struct sdw_bus *bus, struct device *parent,
                return ret;
        }
 
+       ida_init(&bus->slave_ida);
+
        ret = sdw_master_device_add(bus, parent, fwnode);
        if (ret < 0) {
                dev_err(parent, "Failed to add master device at link %d\n",
index e98d5db81b1ced347b62478df62949f0e76e081a..75d6f16efcedb45d36b6c95c05d0fd3a7715264c 100644 (file)
@@ -105,9 +105,17 @@ static int sdw_drv_probe(struct device *dev)
        if (ret)
                return ret;
 
+       ret = ida_alloc_max(&slave->bus->slave_ida, SDW_FW_MAX_DEVICES, GFP_KERNEL);
+       if (ret < 0) {
+               dev_err(dev, "Failed to allocated ID: %d\n", ret);
+               return ret;
+       }
+       slave->index = ret;
+
        ret = drv->probe(slave, id);
        if (ret) {
                dev_pm_domain_detach(dev, false);
+               ida_free(&slave->bus->slave_ida, slave->index);
                return ret;
        }
 
@@ -174,6 +182,8 @@ static int sdw_drv_remove(struct device *dev)
 
        dev_pm_domain_detach(dev, false);
 
+       ida_free(&slave->bus->slave_ida, slave->index);
+
        return ret;
 }
 
index c237e6d0766b330c77515641ea143667e334716d..f18be37efef8e0ef63bad159cc0d9ebb619a89bf 100644 (file)
@@ -31,7 +31,7 @@ int sdw_irq_create(struct sdw_bus *bus,
 {
        bus->irq_chip.name = dev_name(bus->dev);
 
-       bus->domain = irq_domain_create_linear(fwnode, SDW_MAX_DEVICES,
+       bus->domain = irq_domain_create_linear(fwnode, SDW_FW_MAX_DEVICES,
                                               &sdw_domain_ops, bus);
        if (!bus->domain) {
                dev_err(bus->dev, "Failed to add IRQ domain\n");
@@ -50,12 +50,12 @@ static void sdw_irq_dispose_mapping(void *data)
 {
        struct sdw_slave *slave = data;
 
-       irq_dispose_mapping(irq_find_mapping(slave->bus->domain, slave->dev_num));
+       irq_dispose_mapping(slave->irq);
 }
 
 void sdw_irq_create_mapping(struct sdw_slave *slave)
 {
-       slave->irq = irq_create_mapping(slave->bus->domain, slave->dev_num);
+       slave->irq = irq_create_mapping(slave->bus->domain, slave->index);
        if (!slave->irq)
                dev_warn(&slave->dev, "Failed to map IRQ\n");
 
index 2362f621d94c26612abc4d6ea0ffce20b97406ba..0832776262ac3beb3f5a31de00174588754f3403 100644 (file)
@@ -8,6 +8,7 @@
 #include <linux/bug.h>
 #include <linux/completion.h>
 #include <linux/device.h>
+#include <linux/idr.h>
 #include <linux/irq.h>
 #include <linux/irqdomain.h>
 #include <linux/lockdep_types.h>
@@ -50,6 +51,7 @@ struct sdw_slave;
 
 #define SDW_FRAME_CTRL_BITS            48
 #define SDW_MAX_DEVICES                        11
+#define SDW_FW_MAX_DEVICES             16
 
 #define SDW_MAX_PORTS                  15
 #define SDW_VALID_PORT_RANGE(n)                ((n) < SDW_MAX_PORTS && (n) >= 1)
@@ -630,6 +632,7 @@ struct sdw_slave_ops {
  * struct sdw_slave - SoundWire Slave
  * @id: MIPI device ID
  * @dev: Linux device
+ * @index: internal ID for this slave
  * @irq: IRQ number
  * @status: Status reported by the Slave
  * @bus: Bus handle
@@ -661,6 +664,7 @@ struct sdw_slave_ops {
 struct sdw_slave {
        struct sdw_slave_id id;
        struct device dev;
+       int index;
        int irq;
        enum sdw_slave_status status;
        struct sdw_bus *bus;
@@ -968,6 +972,7 @@ struct sdw_stream_runtime {
  * @md: Master device
  * @bus_lock_key: bus lock key associated to @bus_lock
  * @bus_lock: bus lock
+ * @slave_ida: IDA for allocating internal slave IDs
  * @slaves: list of Slaves on this bus
  * @msg_lock_key: message lock key associated to @msg_lock
  * @msg_lock: message lock
@@ -1010,6 +1015,7 @@ struct sdw_bus {
        struct sdw_master_device *md;
        struct lock_class_key bus_lock_key;
        struct mutex bus_lock;
+       struct ida slave_ida;
        struct list_head slaves;
        struct lock_class_key msg_lock_key;
        struct mutex msg_lock;