4 * Copyright (C) ST-Ericsson AB 2010
5 * Author: Sjur Brendeland
6 * License terms: GNU General Public License (GPL) version 2
9 #define pr_fmt(fmt) KBUILD_MODNAME ":%s(): " fmt, __func__
11 #include <linux/stddef.h>
12 #include <linux/spinlock.h>
13 #include <linux/slab.h>
14 #include <linux/crc-ccitt.h>
15 #include <linux/netdevice.h>
16 #include <net/caif/caif_layer.h>
17 #include <net/caif/cfpkt.h>
18 #include <net/caif/cffrml.h>
20 #define container_obj(layr) container_of(layr, struct cffrml, layer)
24 bool dofcs
; /* !< FCS active */
25 int __percpu
*pcpu_refcnt
;
28 static int cffrml_receive(struct cflayer
*layr
, struct cfpkt
*pkt
);
29 static int cffrml_transmit(struct cflayer
*layr
, struct cfpkt
*pkt
);
30 static void cffrml_ctrlcmd(struct cflayer
*layr
, enum caif_ctrlcmd ctrl
,
33 static u32 cffrml_rcv_error
;
34 static u32 cffrml_rcv_checsum_error
;
35 struct cflayer
*cffrml_create(u16 phyid
, bool use_fcs
)
37 struct cffrml
*this = kzalloc(sizeof(struct cffrml
), GFP_ATOMIC
);
40 this->pcpu_refcnt
= alloc_percpu(int);
41 if (this->pcpu_refcnt
== NULL
) {
46 caif_assert(offsetof(struct cffrml
, layer
) == 0);
48 this->layer
.receive
= cffrml_receive
;
49 this->layer
.transmit
= cffrml_transmit
;
50 this->layer
.ctrlcmd
= cffrml_ctrlcmd
;
51 snprintf(this->layer
.name
, CAIF_LAYER_NAME_SZ
, "frm%d", phyid
);
52 this->dofcs
= use_fcs
;
53 this->layer
.id
= phyid
;
54 return (struct cflayer
*) this;
57 void cffrml_free(struct cflayer
*layer
)
59 struct cffrml
*this = container_obj(layer
);
60 free_percpu(this->pcpu_refcnt
);
64 void cffrml_set_uplayer(struct cflayer
*this, struct cflayer
*up
)
69 void cffrml_set_dnlayer(struct cflayer
*this, struct cflayer
*dn
)
74 static u16
cffrml_checksum(u16 chks
, void *buf
, u16 len
)
76 /* FIXME: FCS should be moved to glue in order to use OS-Specific
79 return crc_ccitt(chks
, buf
, len
);
82 static int cffrml_receive(struct cflayer
*layr
, struct cfpkt
*pkt
)
89 this = container_obj(layr
);
91 cfpkt_extr_head(pkt
, &tmp
, 2);
92 len
= le16_to_cpu(tmp
);
94 /* Subtract for FCS on length if FCS is not used. */
98 if (cfpkt_setlen(pkt
, len
) < 0) {
100 pr_err("Framing length error (%d)\n", len
);
105 * Don't do extract if FCS is false, rather do setlen - then we don't
109 cfpkt_extr_trail(pkt
, &tmp
, 2);
110 hdrchks
= le16_to_cpu(tmp
);
111 pktchks
= cfpkt_iterate(pkt
, cffrml_checksum
, 0xffff);
112 if (pktchks
!= hdrchks
) {
113 cfpkt_add_trail(pkt
, &tmp
, 2);
115 ++cffrml_rcv_checsum_error
;
116 pr_info("Frame checksum error (0x%x != 0x%x)\n",
121 if (cfpkt_erroneous(pkt
)) {
123 pr_err("Packet is erroneous!\n");
128 if (layr
->up
== NULL
) {
129 pr_err("Layr up is missing!\n");
134 return layr
->up
->receive(layr
->up
, pkt
);
137 static int cffrml_transmit(struct cflayer
*layr
, struct cfpkt
*pkt
)
143 struct cffrml
*this = container_obj(layr
);
145 chks
= cfpkt_iterate(pkt
, cffrml_checksum
, 0xffff);
146 data
= cpu_to_le16(chks
);
147 cfpkt_add_trail(pkt
, &data
, 2);
149 cfpkt_pad_trail(pkt
, 2);
151 len
= cfpkt_getlen(pkt
);
152 data
= cpu_to_le16(len
);
153 cfpkt_add_head(pkt
, &data
, 2);
154 cfpkt_info(pkt
)->hdr_len
+= 2;
155 if (cfpkt_erroneous(pkt
)) {
156 pr_err("Packet is erroneous!\n");
161 if (layr
->dn
== NULL
) {
166 return layr
->dn
->transmit(layr
->dn
, pkt
);
169 static void cffrml_ctrlcmd(struct cflayer
*layr
, enum caif_ctrlcmd ctrl
,
172 if (layr
->up
&& layr
->up
->ctrlcmd
)
173 layr
->up
->ctrlcmd(layr
->up
, ctrl
, layr
->id
);
176 void cffrml_put(struct cflayer
*layr
)
178 struct cffrml
*this = container_obj(layr
);
179 if (layr
!= NULL
&& this->pcpu_refcnt
!= NULL
)
180 this_cpu_dec(*this->pcpu_refcnt
);
183 void cffrml_hold(struct cflayer
*layr
)
185 struct cffrml
*this = container_obj(layr
);
186 if (layr
!= NULL
&& this->pcpu_refcnt
!= NULL
)
187 this_cpu_inc(*this->pcpu_refcnt
);
190 int cffrml_refcnt_read(struct cflayer
*layr
)
193 struct cffrml
*this = container_obj(layr
);
194 for_each_possible_cpu(i
)
195 refcnt
+= *per_cpu_ptr(this->pcpu_refcnt
, i
);