Skip to content

Commit

Permalink
soc: qcom: apr: make code more reuseable
Browse files Browse the repository at this point in the history
APR and other packet routers like GPR are pretty much same and
interact with other drivers in similar way.

Ex: GPR ports can be considered as APR services, only difference
is they are allocated dynamically.

Other difference is packet layout, which should not matter
with the apis abstracted. Apart from this the rest of the
functionality is pretty much identical across APR and GPR.

Make the apr code more reusable by abstracting it service level,
rather than device level so that we do not need to write
new drivers for other new packet routers like GPR.

This patch is in preparation to add GPR support to this driver.

Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
  • Loading branch information
Srinivas-Kandagatla authored and intel-lab-lkp committed Jul 14, 2021
1 parent e3864c6 commit 16cc55d
Show file tree
Hide file tree
Showing 2 changed files with 79 additions and 45 deletions.
113 changes: 69 additions & 44 deletions drivers/soc/qcom/apr.c
Expand Up @@ -15,13 +15,18 @@
#include <linux/rpmsg.h>
#include <linux/of.h>

struct apr {
enum {
PR_TYPE_APR = 0,
};

struct packet_router {
struct rpmsg_endpoint *ch;
struct device *dev;
spinlock_t svcs_lock;
spinlock_t rx_lock;
struct idr svcs_idr;
int dest_domain_id;
int type;
struct pdr_handle *pdr;
struct workqueue_struct *rxwq;
struct work_struct rx_work;
Expand All @@ -44,21 +49,21 @@ struct apr_rx_buf {
*/
int apr_send_pkt(struct apr_device *adev, struct apr_pkt *pkt)
{
struct apr *apr = dev_get_drvdata(adev->dev.parent);
struct packet_router *apr = dev_get_drvdata(adev->dev.parent);
struct apr_hdr *hdr;
unsigned long flags;
int ret;

spin_lock_irqsave(&adev->lock, flags);
spin_lock_irqsave(&adev->svc.lock, flags);

hdr = &pkt->hdr;
hdr->src_domain = APR_DOMAIN_APPS;
hdr->src_svc = adev->svc_id;
hdr->src_svc = adev->svc.id;
hdr->dest_domain = adev->domain_id;
hdr->dest_svc = adev->svc_id;
hdr->dest_svc = adev->svc.id;

ret = rpmsg_trysend(apr->ch, pkt, hdr->pkt_size);
spin_unlock_irqrestore(&adev->lock, flags);
spin_unlock_irqrestore(&adev->svc.lock, flags);

return ret ? ret : hdr->pkt_size;
}
Expand All @@ -74,7 +79,7 @@ static void apr_dev_release(struct device *dev)
static int apr_callback(struct rpmsg_device *rpdev, void *buf,
int len, void *priv, u32 addr)
{
struct apr *apr = dev_get_drvdata(&rpdev->dev);
struct packet_router *apr = dev_get_drvdata(&rpdev->dev);
struct apr_rx_buf *abuf;
unsigned long flags;

Expand All @@ -100,8 +105,7 @@ static int apr_callback(struct rpmsg_device *rpdev, void *buf,
return 0;
}


static int apr_do_rx_callback(struct apr *apr, struct apr_rx_buf *abuf)
static int apr_do_rx_callback(struct packet_router *apr, struct apr_rx_buf *abuf)
{
uint16_t hdr_size, msg_type, ver, svc_id;
struct apr_device *svc = NULL;
Expand Down Expand Up @@ -171,13 +175,19 @@ static int apr_do_rx_callback(struct apr *apr, struct apr_rx_buf *abuf)

static void apr_rxwq(struct work_struct *work)
{
struct apr *apr = container_of(work, struct apr, rx_work);
struct packet_router *apr = container_of(work, struct packet_router, rx_work);
struct apr_rx_buf *abuf, *b;
unsigned long flags;

if (!list_empty(&apr->rx_list)) {
list_for_each_entry_safe(abuf, b, &apr->rx_list, node) {
apr_do_rx_callback(apr, abuf);
switch (apr->type) {
case PR_TYPE_APR:
apr_do_rx_callback(apr, abuf);
break;
default:
break;
}
spin_lock_irqsave(&apr->rx_lock, flags);
list_del(&abuf->node);
spin_unlock_irqrestore(&apr->rx_lock, flags);
Expand All @@ -201,7 +211,7 @@ static int apr_device_match(struct device *dev, struct device_driver *drv)

while (id->domain_id != 0 || id->svc_id != 0) {
if (id->domain_id == adev->domain_id &&
id->svc_id == adev->svc_id)
id->svc_id == adev->svc.id)
return 1;
id++;
}
Expand All @@ -221,14 +231,14 @@ static int apr_device_remove(struct device *dev)
{
struct apr_device *adev = to_apr_device(dev);
struct apr_driver *adrv;
struct apr *apr = dev_get_drvdata(adev->dev.parent);
struct packet_router *apr = dev_get_drvdata(adev->dev.parent);

if (dev->driver) {
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);
idr_remove(&apr->svcs_idr, adev->svc.id);
spin_unlock(&apr->svcs_lock);
}

Expand Down Expand Up @@ -257,28 +267,39 @@ struct bus_type aprbus = {
EXPORT_SYMBOL_GPL(aprbus);

static int apr_add_device(struct device *dev, struct device_node *np,
const struct apr_device_id *id)
u32 svc_id, u32 domain_id)
{
struct apr *apr = dev_get_drvdata(dev);
struct packet_router *apr = dev_get_drvdata(dev);
struct apr_device *adev = NULL;
struct pkt_router_svc *svc;
int ret;

adev = kzalloc(sizeof(*adev), GFP_KERNEL);
if (!adev)
return -ENOMEM;

spin_lock_init(&adev->lock);
adev->svc_id = svc_id;
svc = &adev->svc;

svc->id = svc_id;
svc->pr = apr;
svc->priv = adev;
svc->dev = dev;
spin_lock_init(&svc->lock);

adev->domain_id = domain_id;

adev->svc_id = id->svc_id;
adev->domain_id = id->domain_id;
adev->version = id->svc_version;
if (np)
snprintf(adev->name, APR_NAME_SIZE, "%pOFn", np);
else
strscpy(adev->name, id->name, APR_NAME_SIZE);

dev_set_name(&adev->dev, "aprsvc:%s:%x:%x", adev->name,
id->domain_id, id->svc_id);
switch (apr->type) {
case PR_TYPE_APR:
dev_set_name(&adev->dev, "aprsvc:%s:%x:%x", adev->name,
domain_id, svc_id);
break;
default:
break;
}

adev->dev.bus = &aprbus;
adev->dev.parent = dev;
Expand All @@ -287,8 +308,7 @@ static int apr_add_device(struct device *dev, struct device_node *np,
adev->dev.driver = NULL;

spin_lock(&apr->svcs_lock);
idr_alloc(&apr->svcs_idr, adev, id->svc_id,
id->svc_id + 1, GFP_ATOMIC);
idr_alloc(&apr->svcs_idr, svc, svc_id, svc_id + 1, GFP_ATOMIC);
spin_unlock(&apr->svcs_lock);

of_property_read_string_index(np, "qcom,protection-domain",
Expand All @@ -308,7 +328,7 @@ static int apr_add_device(struct device *dev, struct device_node *np,
static int of_apr_add_pd_lookups(struct device *dev)
{
const char *service_name, *service_path;
struct apr *apr = dev_get_drvdata(dev);
struct packet_router *apr = dev_get_drvdata(dev);
struct device_node *node;
struct pdr_service *pds;
int ret;
Expand Down Expand Up @@ -338,13 +358,14 @@ static int of_apr_add_pd_lookups(struct device *dev)

static void of_register_apr_devices(struct device *dev, const char *svc_path)
{
struct apr *apr = dev_get_drvdata(dev);
struct packet_router *apr = dev_get_drvdata(dev);
struct device_node *node;
const char *service_path;
int ret;

for_each_child_of_node(dev->of_node, node) {
struct apr_device_id id = { {0} };
u32 svc_id;
u32 domain_id;

/*
* This function is called with svc_path NULL during
Expand Down Expand Up @@ -374,13 +395,13 @@ static void of_register_apr_devices(struct device *dev, const char *svc_path)
continue;
}

if (of_property_read_u32(node, "reg", &id.svc_id))
if (of_property_read_u32(node, "reg", &svc_id))
continue;

id.domain_id = apr->dest_domain_id;
domain_id = apr->dest_domain_id;

if (apr_add_device(dev, node, &id))
dev_err(dev, "Failed to add apr %d svc\n", id.svc_id);
if (apr_add_device(dev, node, svc_id, domain_id))
dev_err(dev, "Failed to add apr %d svc\n", svc_id);
}
}

Expand All @@ -400,7 +421,7 @@ static int apr_remove_device(struct device *dev, void *svc_path)

static void apr_pd_status(int state, char *svc_path, void *priv)
{
struct apr *apr = (struct apr *)priv;
struct packet_router *apr = (struct packet_router *)priv;

switch (state) {
case SERVREG_SERVICE_STATE_UP:
Expand All @@ -415,16 +436,20 @@ static void apr_pd_status(int state, char *svc_path, void *priv)
static int apr_probe(struct rpmsg_device *rpdev)
{
struct device *dev = &rpdev->dev;
struct apr *apr;
struct packet_router *apr;
int ret;

apr = devm_kzalloc(dev, sizeof(*apr), GFP_KERNEL);
if (!apr)
return -ENOMEM;

ret = of_property_read_u32(dev->of_node, "qcom,apr-domain", &apr->dest_domain_id);
if (of_device_is_compatible(dev->of_node, "qcom,apr")) {
ret = of_property_read_u32(dev->of_node, "qcom,apr-domain", &apr->dest_domain_id);
apr->type = PR_TYPE_APR;
}

if (ret) {
dev_err(dev, "APR Domain ID not specified in DT\n");
dev_err(dev, "Domain ID not specified in DT\n");
return ret;
}

Expand Down Expand Up @@ -467,7 +492,7 @@ static int apr_probe(struct rpmsg_device *rpdev)

static void apr_remove(struct rpmsg_device *rpdev)
{
struct apr *apr = dev_get_drvdata(&rpdev->dev);
struct packet_router *apr = dev_get_drvdata(&rpdev->dev);

pdr_handle_release(apr->pdr);
device_for_each_child(&rpdev->dev, NULL, apr_remove_device);
Expand Down Expand Up @@ -504,20 +529,20 @@ void apr_driver_unregister(struct apr_driver *drv)
}
EXPORT_SYMBOL_GPL(apr_driver_unregister);

static const struct of_device_id apr_of_match[] = {
static const struct of_device_id pkt_router_of_match[] = {
{ .compatible = "qcom,apr"},
{ .compatible = "qcom,apr-v2"},
{}
};
MODULE_DEVICE_TABLE(of, apr_of_match);
MODULE_DEVICE_TABLE(of, pkt_router_of_match);

static struct rpmsg_driver apr_driver = {
static struct rpmsg_driver packet_router_driver = {
.probe = apr_probe,
.remove = apr_remove,
.callback = apr_callback,
.drv = {
.name = "qcom,apr",
.of_match_table = apr_of_match,
.of_match_table = pkt_router_of_match,
},
};

Expand All @@ -527,7 +552,7 @@ static int __init apr_init(void)

ret = bus_register(&aprbus);
if (!ret)
ret = register_rpmsg_driver(&apr_driver);
ret = register_rpmsg_driver(&packet_router_driver);
else
bus_unregister(&aprbus);

Expand All @@ -537,7 +562,7 @@ static int __init apr_init(void)
static void __exit apr_exit(void)
{
bus_unregister(&aprbus);
unregister_rpmsg_driver(&apr_driver);
unregister_rpmsg_driver(&packet_router_driver);
}

subsys_initcall(apr_init);
Expand Down
11 changes: 10 additions & 1 deletion include/linux/soc/qcom/apr.h
Expand Up @@ -79,14 +79,23 @@ struct apr_resp_pkt {
#define APR_SVC_MAJOR_VERSION(v) ((v >> 16) & 0xFF)
#define APR_SVC_MINOR_VERSION(v) (v & 0xFF)

struct packet_router;
struct pkt_router_svc {
struct device *dev;
struct packet_router *pr;
spinlock_t lock;
int id;
void *priv;
};

struct apr_device {
struct device dev;
uint16_t svc_id;
uint16_t domain_id;
uint32_t version;
char name[APR_NAME_SIZE];
const char *service_path;
spinlock_t lock;
struct pkt_router_svc svc;
struct list_head node;
};

Expand Down

0 comments on commit 16cc55d

Please sign in to comment.