Commit cb3cb423 authored by sjur.brandeland@stericsson.com's avatar sjur.brandeland@stericsson.com Committed by David S. Miller

caif: Add ref-count to framing layer

Introduce Per-cpu reference for lower part of CAIF Stack.
Before freeing payload is disabled, synchronize_rcu() is called,
and then ref-count verified to be zero.
Signed-off-by: default avatarSjur Brændeland <sjur.brandeland@stericsson.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent f3621440
...@@ -7,12 +7,15 @@ ...@@ -7,12 +7,15 @@
#ifndef CFFRML_H_ #ifndef CFFRML_H_
#define CFFRML_H_ #define CFFRML_H_
#include <net/caif/caif_layer.h> #include <net/caif/caif_layer.h>
#include <linux/netdevice.h>
struct cffrml; struct cffrml;
struct cflayer *cffrml_create(u16 phyid, bool DoFCS); struct cflayer *cffrml_create(u16 phyid, bool use_fcs);
void cffrml_free(struct cflayer *layr);
void cffrml_set_uplayer(struct cflayer *this, struct cflayer *up); void cffrml_set_uplayer(struct cflayer *this, struct cflayer *up);
void cffrml_set_dnlayer(struct cflayer *this, struct cflayer *dn); void cffrml_set_dnlayer(struct cflayer *this, struct cflayer *dn);
void cffrml_put(struct cflayer *layr); void cffrml_put(struct cflayer *layr);
void cffrml_hold(struct cflayer *layr); void cffrml_hold(struct cflayer *layr);
int cffrml_refcnt_read(struct cflayer *layr);
#endif /* CFFRML_H_ */ #endif /* CFFRML_H_ */
...@@ -519,6 +519,13 @@ int cfcnfg_del_phy_layer(struct cfcnfg *cnfg, struct cflayer *phy_layer) ...@@ -519,6 +519,13 @@ int cfcnfg_del_phy_layer(struct cfcnfg *cnfg, struct cflayer *phy_layer)
caif_assert(phy_layer->id == phyid); caif_assert(phy_layer->id == phyid);
caif_assert(phyinfo->frm_layer->id == phyid); caif_assert(phyinfo->frm_layer->id == phyid);
/* Fail if reference count is not zero */
if (cffrml_refcnt_read(phyinfo->frm_layer) != 0) {
pr_info("Wait for device inuse\n");
mutex_unlock(&cnfg->lock);
return -EAGAIN;
}
list_del_rcu(&phyinfo->node); list_del_rcu(&phyinfo->node);
synchronize_rcu(); synchronize_rcu();
...@@ -537,7 +544,7 @@ int cfcnfg_del_phy_layer(struct cfcnfg *cnfg, struct cflayer *phy_layer) ...@@ -537,7 +544,7 @@ int cfcnfg_del_phy_layer(struct cfcnfg *cnfg, struct cflayer *phy_layer)
if (phyinfo->phy_layer != frml_dn) if (phyinfo->phy_layer != frml_dn)
kfree(frml_dn); kfree(frml_dn);
kfree(frml); cffrml_free(frml);
kfree(phyinfo); kfree(phyinfo);
mutex_unlock(&cnfg->lock); mutex_unlock(&cnfg->lock);
......
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
#include <linux/spinlock.h> #include <linux/spinlock.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/crc-ccitt.h> #include <linux/crc-ccitt.h>
#include <linux/netdevice.h>
#include <net/caif/caif_layer.h> #include <net/caif/caif_layer.h>
#include <net/caif/cfpkt.h> #include <net/caif/cfpkt.h>
#include <net/caif/cffrml.h> #include <net/caif/cffrml.h>
...@@ -21,6 +22,7 @@ ...@@ -21,6 +22,7 @@
struct cffrml { struct cffrml {
struct cflayer layer; struct cflayer layer;
bool dofcs; /* !< FCS active */ bool dofcs; /* !< FCS active */
int __percpu *pcpu_refcnt;
}; };
static int cffrml_receive(struct cflayer *layr, struct cfpkt *pkt); static int cffrml_receive(struct cflayer *layr, struct cfpkt *pkt);
...@@ -31,12 +33,19 @@ static void cffrml_ctrlcmd(struct cflayer *layr, enum caif_ctrlcmd ctrl, ...@@ -31,12 +33,19 @@ static void cffrml_ctrlcmd(struct cflayer *layr, enum caif_ctrlcmd ctrl,
static u32 cffrml_rcv_error; static u32 cffrml_rcv_error;
static u32 cffrml_rcv_checsum_error; static u32 cffrml_rcv_checsum_error;
struct cflayer *cffrml_create(u16 phyid, bool use_fcs) struct cflayer *cffrml_create(u16 phyid, bool use_fcs)
{ {
struct cffrml *this = kmalloc(sizeof(struct cffrml), GFP_ATOMIC); struct cffrml *this = kmalloc(sizeof(struct cffrml), GFP_ATOMIC);
if (!this) { if (!this) {
pr_warn("Out of memory\n"); pr_warn("Out of memory\n");
return NULL; return NULL;
} }
this->pcpu_refcnt = alloc_percpu(int);
if (this->pcpu_refcnt == NULL) {
kfree(this);
return NULL;
}
caif_assert(offsetof(struct cffrml, layer) == 0); caif_assert(offsetof(struct cffrml, layer) == 0);
memset(this, 0, sizeof(struct cflayer)); memset(this, 0, sizeof(struct cflayer));
...@@ -49,6 +58,13 @@ struct cflayer *cffrml_create(u16 phyid, bool use_fcs) ...@@ -49,6 +58,13 @@ struct cflayer *cffrml_create(u16 phyid, bool use_fcs)
return (struct cflayer *) this; return (struct cflayer *) this;
} }
void cffrml_free(struct cflayer *layer)
{
struct cffrml *this = container_obj(layer);
free_percpu(this->pcpu_refcnt);
kfree(layer);
}
void cffrml_set_uplayer(struct cflayer *this, struct cflayer *up) void cffrml_set_uplayer(struct cflayer *this, struct cflayer *up)
{ {
this->up = up; this->up = up;
...@@ -148,8 +164,23 @@ static void cffrml_ctrlcmd(struct cflayer *layr, enum caif_ctrlcmd ctrl, ...@@ -148,8 +164,23 @@ static void cffrml_ctrlcmd(struct cflayer *layr, enum caif_ctrlcmd ctrl,
void cffrml_put(struct cflayer *layr) void cffrml_put(struct cflayer *layr)
{ {
struct cffrml *this = container_obj(layr);
if (layr != NULL && this->pcpu_refcnt != NULL)
irqsafe_cpu_dec(*this->pcpu_refcnt);
} }
void cffrml_hold(struct cflayer *layr) void cffrml_hold(struct cflayer *layr)
{ {
struct cffrml *this = container_obj(layr);
if (layr != NULL && this->pcpu_refcnt != NULL)
irqsafe_cpu_inc(*this->pcpu_refcnt);
}
int cffrml_refcnt_read(struct cflayer *layr)
{
int i, refcnt = 0;
struct cffrml *this = container_obj(layr);
for_each_possible_cpu(i)
refcnt += *per_cpu_ptr(this->pcpu_refcnt, i);
return refcnt;
} }
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment