#include <linux/module.h>
#include <linux/device.h>
#include <linux/spinlock.h>
-#include <linux/idr.h>
#include <linux/slab.h>
#include <linux/workqueue.h>
#include <linux/of_device.h>
#include <linux/soc/qcom/apr.h>
#include <linux/rpmsg.h>
#include <linux/of.h>
+#include <linux/xarray.h>
struct apr {
struct rpmsg_endpoint *ch;
struct device *dev;
- spinlock_t svcs_lock;
spinlock_t rx_lock;
- struct idr svcs_idr;
+ struct xarray svcs;
int dest_domain_id;
struct workqueue_struct *rxwq;
struct work_struct rx_work;
return -EINVAL;
}
- svc_id = hdr->dest_svc;
- spin_lock_irqsave(&apr->svcs_lock, flags);
- svc = idr_find(&apr->svcs_idr, svc_id);
+ svc = xa_load(&apr->svcs, hdr->dest_svc);
if (svc && svc->dev.driver)
adrv = to_apr_driver(svc->dev.driver);
- spin_unlock_irqrestore(&apr->svcs_lock, flags);
if (!adrv) {
dev_err(apr->dev, "APR: service is not registered\n");
adrv = to_apr_driver(dev->driver);
if (adrv->remove)
adrv->remove(adev);
- spin_lock(&apr->svcs_lock);
- idr_remove(&apr->svcs_idr, adev->svc_id);
- spin_unlock(&apr->svcs_lock);
+ xa_erase(&apr->svcs, adev->svc_id);
}
return 0;
adev->dev.release = apr_dev_release;
adev->dev.driver = NULL;
- spin_lock(&apr->svcs_lock);
- idr_alloc(&apr->svcs_idr, adev, id->svc_id,
- id->svc_id + 1, GFP_ATOMIC);
- spin_unlock(&apr->svcs_lock);
+ ret = xa_insert(&apr->svcs, adev->svc_id, adev, GFP_KERNEL);
+ if (ret < 0) {
+ put_device(&adev->dev);
+ return ret;
+ }
dev_info(dev, "Adding APR dev: %s\n", dev_name(&adev->dev));
ret = device_register(&adev->dev);
if (ret) {
dev_err(dev, "device_register failed: %d\n", ret);
+ xa_erase(&apr->svcs, adev->svc_id);
put_device(&adev->dev);
}
INIT_WORK(&apr->rx_work, apr_rxwq);
INIT_LIST_HEAD(&apr->rx_list);
spin_lock_init(&apr->rx_lock);
- spin_lock_init(&apr->svcs_lock);
- idr_init(&apr->svcs_idr);
+ xa_init(&apr->svcs);
of_register_apr_devices(dev);
return 0;