]> www.infradead.org Git - users/willy/xarray.git/commitdiff
rpmsg: Convert lcids to XArray
authorMatthew Wilcox <willy@infradead.org>
Tue, 8 Jan 2019 17:07:21 +0000 (12:07 -0500)
committerMatthew Wilcox (Oracle) <willy@infradead.org>
Fri, 9 Aug 2019 01:38:14 +0000 (21:38 -0400)
Signed-off-by: Matthew Wilcox <willy@infradead.org>
drivers/rpmsg/qcom_glink_native.c

index f46c787733e8ac6ac63cf5eca85a40cad0665272..a177d13a1c4e0c2947a764b152dc384f8d624d70 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/sizes.h>
 #include <linux/slab.h>
 #include <linux/workqueue.h>
+#include <linux/xarray.h>
 #include <linux/mailbox_client.h>
 
 #include "rpmsg_internal.h"
@@ -26,9 +27,6 @@
 #define GLINK_NAME_SIZE                32
 #define GLINK_VERSION_1                1
 
-#define RPM_GLINK_CID_MIN      1
-#define RPM_GLINK_CID_MAX      65536
-
 struct glink_msg {
        __le16 cmd;
        __le16 param1;
@@ -87,8 +85,8 @@ struct glink_core_rx_intent {
  * @rx_lock:   protects the @rx_queue
  * @rx_queue:  queue of received control messages to be processed in @rx_work
  * @tx_lock:   synchronizes operations on the tx fifo
- * @idr_lock:  synchronizes @lcids and @rcids modifications
- * @lcids:     idr of all channels with a known local channel id
+ * @idr_lock:  synchronizes @rcids modifications
+ * @lcids:     all channels with a known local channel id
  * @rcids:     idr of all channels with a known remote channel id
  * @features:  remote features
  * @intentless:        flag to indicate that there is no intent
@@ -113,7 +111,8 @@ struct qcom_glink {
        spinlock_t tx_lock;
 
        spinlock_t idr_lock;
-       struct idr lcids;
+       u32 lcid_next;
+       struct xarray lcids;
        struct idr rcids;
        unsigned long features;
 
@@ -391,37 +390,25 @@ static int qcom_glink_send_open_req(struct qcom_glink *glink,
        int name_len = strlen(channel->name) + 1;
        int req_len = ALIGN(sizeof(req.msg) + name_len, 8);
        int ret;
-       unsigned long flags;
 
        kref_get(&channel->refcount);
 
-       spin_lock_irqsave(&glink->idr_lock, flags);
-       ret = idr_alloc_cyclic(&glink->lcids, channel,
-                              RPM_GLINK_CID_MIN, RPM_GLINK_CID_MAX,
-                              GFP_ATOMIC);
-       spin_unlock_irqrestore(&glink->idr_lock, flags);
+       ret = xa_alloc_cyclic_irq(&glink->lcids, &channel->lcid, channel,
+                       XA_LIMIT(1, 65535), &glink->lcid_next, GFP_KERNEL);
        if (ret < 0)
                return ret;
 
-       channel->lcid = ret;
-
        req.msg.cmd = cpu_to_le16(RPM_CMD_OPEN);
        req.msg.param1 = cpu_to_le16(channel->lcid);
        req.msg.param2 = cpu_to_le32(name_len);
        strcpy(req.name, channel->name);
 
        ret = qcom_glink_tx(glink, &req, req_len, NULL, 0, true);
-       if (ret)
-               goto remove_idr;
-
-       return 0;
+       if (!ret)
+               return 0;
 
-remove_idr:
-       spin_lock_irqsave(&glink->idr_lock, flags);
-       idr_remove(&glink->lcids, channel->lcid);
+       xa_erase_irq(&glink->lcids, channel->lcid);
        channel->lcid = 0;
-       spin_unlock_irqrestore(&glink->idr_lock, flags);
-
        return ret;
 }
 
@@ -941,9 +928,7 @@ static int qcom_glink_rx_open_ack(struct qcom_glink *glink, unsigned int lcid)
 {
        struct glink_channel *channel;
 
-       spin_lock(&glink->idr_lock);
-       channel = idr_find(&glink->lcids, lcid);
-       spin_unlock(&glink->idr_lock);
+       channel = xa_load(&glink->lcids, lcid);
        if (!channel) {
                dev_err(glink->dev, "Invalid open ack packet\n");
                return -EINVAL;
@@ -1034,7 +1019,6 @@ static struct glink_channel *qcom_glink_create_local(struct qcom_glink *glink,
 {
        struct glink_channel *channel;
        int ret;
-       unsigned long flags;
 
        channel = qcom_glink_alloc_channel(glink, name);
        if (IS_ERR(channel))
@@ -1058,9 +1042,7 @@ static struct glink_channel *qcom_glink_create_local(struct qcom_glink *glink,
 
 err_timeout:
        /* qcom_glink_send_open_req() did register the channel in lcids*/
-       spin_lock_irqsave(&glink->idr_lock, flags);
-       idr_remove(&glink->lcids, channel->lcid);
-       spin_unlock_irqrestore(&glink->idr_lock, flags);
+       xa_erase_irq(&glink->lcids, channel->lcid);
 
 release_channel:
        /* Release qcom_glink_send_open_req() reference */
@@ -1363,16 +1345,15 @@ static int qcom_glink_rx_open(struct qcom_glink *glink, unsigned int rcid,
        struct rpmsg_device *rpdev;
        bool create_device = false;
        struct device_node *node;
-       int lcid;
+       unsigned long lcid;
        int ret;
-       unsigned long flags;
 
-       spin_lock_irqsave(&glink->idr_lock, flags);
-       idr_for_each_entry(&glink->lcids, channel, lcid) {
+       xa_lock_irq(&glink->lcids);
+       xa_for_each(&glink->lcids, lcid, channel) {
                if (!strcmp(channel->name, name))
                        break;
        }
-       spin_unlock_irqrestore(&glink->idr_lock, flags);
+       xa_unlock_irq(&glink->lcids);
 
        if (!channel) {
                channel = qcom_glink_alloc_channel(glink, name);
@@ -1383,15 +1364,15 @@ static int qcom_glink_rx_open(struct qcom_glink *glink, unsigned int rcid,
                create_device = true;
        }
 
-       spin_lock_irqsave(&glink->idr_lock, flags);
+       spin_lock_irq(&glink->idr_lock);
        ret = idr_alloc(&glink->rcids, channel, rcid, rcid + 1, GFP_ATOMIC);
        if (ret < 0) {
                dev_err(glink->dev, "Unable to insert channel into rcid list\n");
-               spin_unlock_irqrestore(&glink->idr_lock, flags);
+               spin_unlock_irq(&glink->idr_lock);
                goto free_channel;
        }
        channel->rcid = ret;
-       spin_unlock_irqrestore(&glink->idr_lock, flags);
+       spin_unlock_irq(&glink->idr_lock);
 
        complete(&channel->open_req);
 
@@ -1425,10 +1406,10 @@ static int qcom_glink_rx_open(struct qcom_glink *glink, unsigned int rcid,
 free_rpdev:
        kfree(rpdev);
 rcid_remove:
-       spin_lock_irqsave(&glink->idr_lock, flags);
+       spin_lock_irq(&glink->idr_lock);
        idr_remove(&glink->rcids, channel->rcid);
        channel->rcid = 0;
-       spin_unlock_irqrestore(&glink->idr_lock, flags);
+       spin_unlock_irq(&glink->idr_lock);
 free_channel:
        /* Release the reference, iff we took it */
        if (create_device)
@@ -1475,17 +1456,13 @@ static void qcom_glink_rx_close_ack(struct qcom_glink *glink, unsigned int lcid)
        struct glink_channel *channel;
        unsigned long flags;
 
-       spin_lock_irqsave(&glink->idr_lock, flags);
-       channel = idr_find(&glink->lcids, lcid);
-       if (WARN(!channel, "close ack on unknown channel\n")) {
-               spin_unlock_irqrestore(&glink->idr_lock, flags);
+       xa_lock_irqsave(&glink->lcids, flags);
+       channel = __xa_erase(&glink->lcids, lcid);
+       xa_unlock_irqrestore(&glink->lcids, flags);
+       if (WARN(!channel, "close ack on unknown channel\n"))
                return;
-       }
 
-       idr_remove(&glink->lcids, channel->lcid);
        channel->lcid = 0;
-       spin_unlock_irqrestore(&glink->idr_lock, flags);
-
        kref_put(&channel->refcount, qcom_glink_channel_release);
 }
 
@@ -1571,7 +1548,8 @@ struct qcom_glink *qcom_glink_native_probe(struct device *dev,
        INIT_WORK(&glink->rx_work, qcom_glink_work);
 
        spin_lock_init(&glink->idr_lock);
-       idr_init(&glink->lcids);
+       xa_init_flags(&glink->lcids, XA_FLAGS_ALLOC | XA_FLAGS_LOCK_IRQ);
+       glink->lcid_next = 0;
        idr_init(&glink->rcids);
 
        ret = of_property_read_string(dev->of_node, "label", &glink->name);
@@ -1617,7 +1595,7 @@ static int qcom_glink_remove_device(struct device *dev, void *data)
 void qcom_glink_native_remove(struct qcom_glink *glink)
 {
        struct glink_channel *channel;
-       int cid;
+       unsigned long cid;
        int ret;
        unsigned long flags;
 
@@ -1628,14 +1606,14 @@ void qcom_glink_native_remove(struct qcom_glink *glink)
        if (ret)
                dev_warn(glink->dev, "Can't remove GLINK devices: %d\n", ret);
 
-       spin_lock_irqsave(&glink->idr_lock, flags);
+       xa_lock_irqsave(&glink->lcids, flags);
        /* Release any defunct local channels, waiting for close-ack */
-       idr_for_each_entry(&glink->lcids, channel, cid)
+       xa_for_each(&glink->lcids, cid, channel)
                kref_put(&channel->refcount, qcom_glink_channel_release);
+       xa_unlock_irqrestore(&glink->lcids, flags);
 
-       idr_destroy(&glink->lcids);
+       xa_destroy(&glink->lcids);
        idr_destroy(&glink->rcids);
-       spin_unlock_irqrestore(&glink->idr_lock, flags);
        mbox_free_channel(glink->mbox_chan);
 }
 EXPORT_SYMBOL_GPL(qcom_glink_native_remove);