diff options
author | sjur.brandeland@stericsson.com <sjur.brandeland@stericsson.com> | 2011-05-12 22:44:02 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2011-05-15 17:45:55 -0400 |
commit | cb3cb423a0f3c627639535e5d87977ae662d779f (patch) | |
tree | 37fae151f44b5549bf1d4fd437dd070315d78cad /net/caif | |
parent | f36214408470ecf6a052e76b72d05b2328b60fcf (diff) |
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: Sjur Brændeland <sjur.brandeland@stericsson.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/caif')
-rw-r--r-- | net/caif/cfcnfg.c | 9 | ||||
-rw-r--r-- | net/caif/cffrml.c | 31 |
2 files changed, 39 insertions, 1 deletions
diff --git a/net/caif/cfcnfg.c b/net/caif/cfcnfg.c index 7892cc084e27..3f4f31fca2c1 100644 --- a/net/caif/cfcnfg.c +++ b/net/caif/cfcnfg.c | |||
@@ -519,6 +519,13 @@ int cfcnfg_del_phy_layer(struct cfcnfg *cnfg, struct cflayer *phy_layer) | |||
519 | caif_assert(phy_layer->id == phyid); | 519 | caif_assert(phy_layer->id == phyid); |
520 | caif_assert(phyinfo->frm_layer->id == phyid); | 520 | caif_assert(phyinfo->frm_layer->id == phyid); |
521 | 521 | ||
522 | /* Fail if reference count is not zero */ | ||
523 | if (cffrml_refcnt_read(phyinfo->frm_layer) != 0) { | ||
524 | pr_info("Wait for device inuse\n"); | ||
525 | mutex_unlock(&cnfg->lock); | ||
526 | return -EAGAIN; | ||
527 | } | ||
528 | |||
522 | list_del_rcu(&phyinfo->node); | 529 | list_del_rcu(&phyinfo->node); |
523 | synchronize_rcu(); | 530 | synchronize_rcu(); |
524 | 531 | ||
@@ -537,7 +544,7 @@ int cfcnfg_del_phy_layer(struct cfcnfg *cnfg, struct cflayer *phy_layer) | |||
537 | if (phyinfo->phy_layer != frml_dn) | 544 | if (phyinfo->phy_layer != frml_dn) |
538 | kfree(frml_dn); | 545 | kfree(frml_dn); |
539 | 546 | ||
540 | kfree(frml); | 547 | cffrml_free(frml); |
541 | kfree(phyinfo); | 548 | kfree(phyinfo); |
542 | mutex_unlock(&cnfg->lock); | 549 | mutex_unlock(&cnfg->lock); |
543 | 550 | ||
diff --git a/net/caif/cffrml.c b/net/caif/cffrml.c index f4b88924f83a..4f4f756c49ac 100644 --- a/net/caif/cffrml.c +++ b/net/caif/cffrml.c | |||
@@ -12,6 +12,7 @@ | |||
12 | #include <linux/spinlock.h> | 12 | #include <linux/spinlock.h> |
13 | #include <linux/slab.h> | 13 | #include <linux/slab.h> |
14 | #include <linux/crc-ccitt.h> | 14 | #include <linux/crc-ccitt.h> |
15 | #include <linux/netdevice.h> | ||
15 | #include <net/caif/caif_layer.h> | 16 | #include <net/caif/caif_layer.h> |
16 | #include <net/caif/cfpkt.h> | 17 | #include <net/caif/cfpkt.h> |
17 | #include <net/caif/cffrml.h> | 18 | #include <net/caif/cffrml.h> |
@@ -21,6 +22,7 @@ | |||
21 | struct cffrml { | 22 | struct cffrml { |
22 | struct cflayer layer; | 23 | struct cflayer layer; |
23 | bool dofcs; /* !< FCS active */ | 24 | bool dofcs; /* !< FCS active */ |
25 | int __percpu *pcpu_refcnt; | ||
24 | }; | 26 | }; |
25 | 27 | ||
26 | static int cffrml_receive(struct cflayer *layr, struct cfpkt *pkt); | 28 | 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 | static u32 cffrml_rcv_error; | 33 | static u32 cffrml_rcv_error; |
32 | static u32 cffrml_rcv_checsum_error; | 34 | static u32 cffrml_rcv_checsum_error; |
33 | struct cflayer *cffrml_create(u16 phyid, bool use_fcs) | 35 | struct cflayer *cffrml_create(u16 phyid, bool use_fcs) |
36 | |||
34 | { | 37 | { |
35 | struct cffrml *this = kmalloc(sizeof(struct cffrml), GFP_ATOMIC); | 38 | struct cffrml *this = kmalloc(sizeof(struct cffrml), GFP_ATOMIC); |
36 | if (!this) { | 39 | if (!this) { |
37 | pr_warn("Out of memory\n"); | 40 | pr_warn("Out of memory\n"); |
38 | return NULL; | 41 | return NULL; |
39 | } | 42 | } |
43 | this->pcpu_refcnt = alloc_percpu(int); | ||
44 | if (this->pcpu_refcnt == NULL) { | ||
45 | kfree(this); | ||
46 | return NULL; | ||
47 | } | ||
48 | |||
40 | caif_assert(offsetof(struct cffrml, layer) == 0); | 49 | caif_assert(offsetof(struct cffrml, layer) == 0); |
41 | 50 | ||
42 | memset(this, 0, sizeof(struct cflayer)); | 51 | memset(this, 0, sizeof(struct cflayer)); |
@@ -49,6 +58,13 @@ struct cflayer *cffrml_create(u16 phyid, bool use_fcs) | |||
49 | return (struct cflayer *) this; | 58 | return (struct cflayer *) this; |
50 | } | 59 | } |
51 | 60 | ||
61 | void cffrml_free(struct cflayer *layer) | ||
62 | { | ||
63 | struct cffrml *this = container_obj(layer); | ||
64 | free_percpu(this->pcpu_refcnt); | ||
65 | kfree(layer); | ||
66 | } | ||
67 | |||
52 | void cffrml_set_uplayer(struct cflayer *this, struct cflayer *up) | 68 | void cffrml_set_uplayer(struct cflayer *this, struct cflayer *up) |
53 | { | 69 | { |
54 | this->up = up; | 70 | this->up = up; |
@@ -148,8 +164,23 @@ static void cffrml_ctrlcmd(struct cflayer *layr, enum caif_ctrlcmd ctrl, | |||
148 | 164 | ||
149 | void cffrml_put(struct cflayer *layr) | 165 | void cffrml_put(struct cflayer *layr) |
150 | { | 166 | { |
167 | struct cffrml *this = container_obj(layr); | ||
168 | if (layr != NULL && this->pcpu_refcnt != NULL) | ||
169 | irqsafe_cpu_dec(*this->pcpu_refcnt); | ||
151 | } | 170 | } |
152 | 171 | ||
153 | void cffrml_hold(struct cflayer *layr) | 172 | void cffrml_hold(struct cflayer *layr) |
154 | { | 173 | { |
174 | struct cffrml *this = container_obj(layr); | ||
175 | if (layr != NULL && this->pcpu_refcnt != NULL) | ||
176 | irqsafe_cpu_inc(*this->pcpu_refcnt); | ||
177 | } | ||
178 | |||
179 | int cffrml_refcnt_read(struct cflayer *layr) | ||
180 | { | ||
181 | int i, refcnt = 0; | ||
182 | struct cffrml *this = container_obj(layr); | ||
183 | for_each_possible_cpu(i) | ||
184 | refcnt += *per_cpu_ptr(this->pcpu_refcnt, i); | ||
185 | return refcnt; | ||
155 | } | 186 | } |