diff options
Diffstat (limited to 'net/caif/cffrml.c')
| -rw-r--r-- | net/caif/cffrml.c | 82 |
1 files changed, 63 insertions, 19 deletions
diff --git a/net/caif/cffrml.c b/net/caif/cffrml.c index a445043931a..8bc7caa28e6 100644 --- a/net/caif/cffrml.c +++ b/net/caif/cffrml.c @@ -2,7 +2,7 @@ * CAIF Framing Layer. * * Copyright (C) ST-Ericsson AB 2010 - * Author: Sjur Brendeland/sjur.brandeland@stericsson.com + * Author: Sjur Brendeland * License terms: GNU General Public License (GPL) version 2 */ @@ -12,6 +12,7 @@ #include <linux/spinlock.h> #include <linux/slab.h> #include <linux/crc-ccitt.h> +#include <linux/netdevice.h> #include <net/caif/caif_layer.h> #include <net/caif/cfpkt.h> #include <net/caif/cffrml.h> @@ -21,25 +22,29 @@ struct cffrml { struct cflayer layer; bool dofcs; /* !< FCS active */ + int __percpu *pcpu_refcnt; }; static int cffrml_receive(struct cflayer *layr, struct cfpkt *pkt); static int cffrml_transmit(struct cflayer *layr, struct cfpkt *pkt); static void cffrml_ctrlcmd(struct cflayer *layr, enum caif_ctrlcmd ctrl, - int phyid); + int phyid); static u32 cffrml_rcv_error; static u32 cffrml_rcv_checsum_error; struct cflayer *cffrml_create(u16 phyid, bool use_fcs) { - struct cffrml *this = kmalloc(sizeof(struct cffrml), GFP_ATOMIC); - if (!this) { - pr_warn("Out of memory\n"); + struct cffrml *this = kzalloc(sizeof(struct cffrml), GFP_ATOMIC); + if (!this) + return NULL; + this->pcpu_refcnt = alloc_percpu(int); + if (this->pcpu_refcnt == NULL) { + kfree(this); return NULL; } + caif_assert(offsetof(struct cffrml, layer) == 0); - memset(this, 0, sizeof(struct cflayer)); this->layer.receive = cffrml_receive; this->layer.transmit = cffrml_transmit; this->layer.ctrlcmd = cffrml_ctrlcmd; @@ -49,6 +54,13 @@ struct cflayer *cffrml_create(u16 phyid, bool use_fcs) 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) { this->up = up; @@ -112,42 +124,74 @@ static int cffrml_receive(struct cflayer *layr, struct cfpkt *pkt) cfpkt_destroy(pkt); return -EPROTO; } + + if (layr->up == NULL) { + pr_err("Layr up is missing!\n"); + cfpkt_destroy(pkt); + return -EINVAL; + } + return layr->up->receive(layr->up, pkt); } static int cffrml_transmit(struct cflayer *layr, struct cfpkt *pkt) { - int tmp; u16 chks; u16 len; - int ret; + __le16 data; + struct cffrml *this = container_obj(layr); if (this->dofcs) { chks = cfpkt_iterate(pkt, cffrml_checksum, 0xffff); - tmp = cpu_to_le16(chks); - cfpkt_add_trail(pkt, &tmp, 2); + data = cpu_to_le16(chks); + cfpkt_add_trail(pkt, &data, 2); } else { cfpkt_pad_trail(pkt, 2); } len = cfpkt_getlen(pkt); - tmp = cpu_to_le16(len); - cfpkt_add_head(pkt, &tmp, 2); + data = cpu_to_le16(len); + cfpkt_add_head(pkt, &data, 2); cfpkt_info(pkt)->hdr_len += 2; if (cfpkt_erroneous(pkt)) { pr_err("Packet is erroneous!\n"); + cfpkt_destroy(pkt); return -EPROTO; } - ret = layr->dn->transmit(layr->dn, pkt); - if (ret < 0) { - /* Remove header on faulty packet. */ - cfpkt_extr_head(pkt, &tmp, 2); + + if (layr->dn == NULL) { + cfpkt_destroy(pkt); + return -ENODEV; + } - return ret; + return layr->dn->transmit(layr->dn, pkt); } static void cffrml_ctrlcmd(struct cflayer *layr, enum caif_ctrlcmd ctrl, - int phyid) + int phyid) { - if (layr->up->ctrlcmd) + if (layr->up && layr->up->ctrlcmd) layr->up->ctrlcmd(layr->up, ctrl, layr->id); } + +void cffrml_put(struct cflayer *layr) +{ + struct cffrml *this = container_obj(layr); + if (layr != NULL && this->pcpu_refcnt != NULL) + this_cpu_dec(*this->pcpu_refcnt); +} + +void cffrml_hold(struct cflayer *layr) +{ + struct cffrml *this = container_obj(layr); + if (layr != NULL && this->pcpu_refcnt != NULL) + this_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; +} |
