Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * CAIF Framing Layer.
0004  *
0005  * Copyright (C) ST-Ericsson AB 2010
0006  * Author:  Sjur Brendeland
0007  */
0008 
0009 #define pr_fmt(fmt) KBUILD_MODNAME ":%s(): " fmt, __func__
0010 
0011 #include <linux/stddef.h>
0012 #include <linux/spinlock.h>
0013 #include <linux/slab.h>
0014 #include <linux/crc-ccitt.h>
0015 #include <linux/netdevice.h>
0016 #include <net/caif/caif_layer.h>
0017 #include <net/caif/cfpkt.h>
0018 #include <net/caif/cffrml.h>
0019 
0020 #define container_obj(layr) container_of(layr, struct cffrml, layer)
0021 
0022 struct cffrml {
0023     struct cflayer layer;
0024     bool dofcs;     /* !< FCS active */
0025     int __percpu        *pcpu_refcnt;
0026 };
0027 
0028 static int cffrml_receive(struct cflayer *layr, struct cfpkt *pkt);
0029 static int cffrml_transmit(struct cflayer *layr, struct cfpkt *pkt);
0030 static void cffrml_ctrlcmd(struct cflayer *layr, enum caif_ctrlcmd ctrl,
0031                int phyid);
0032 
0033 static u32 cffrml_rcv_error;
0034 static u32 cffrml_rcv_checsum_error;
0035 struct cflayer *cffrml_create(u16 phyid, bool use_fcs)
0036 {
0037     struct cffrml *this = kzalloc(sizeof(struct cffrml), GFP_ATOMIC);
0038     if (!this)
0039         return NULL;
0040     this->pcpu_refcnt = alloc_percpu(int);
0041     if (this->pcpu_refcnt == NULL) {
0042         kfree(this);
0043         return NULL;
0044     }
0045 
0046     caif_assert(offsetof(struct cffrml, layer) == 0);
0047 
0048     this->layer.receive = cffrml_receive;
0049     this->layer.transmit = cffrml_transmit;
0050     this->layer.ctrlcmd = cffrml_ctrlcmd;
0051     snprintf(this->layer.name, CAIF_LAYER_NAME_SZ, "frm%d", phyid);
0052     this->dofcs = use_fcs;
0053     this->layer.id = phyid;
0054     return (struct cflayer *) this;
0055 }
0056 
0057 void cffrml_free(struct cflayer *layer)
0058 {
0059     struct cffrml *this = container_obj(layer);
0060     free_percpu(this->pcpu_refcnt);
0061     kfree(layer);
0062 }
0063 
0064 void cffrml_set_uplayer(struct cflayer *this, struct cflayer *up)
0065 {
0066     this->up = up;
0067 }
0068 
0069 void cffrml_set_dnlayer(struct cflayer *this, struct cflayer *dn)
0070 {
0071     this->dn = dn;
0072 }
0073 
0074 static u16 cffrml_checksum(u16 chks, void *buf, u16 len)
0075 {
0076     /* FIXME: FCS should be moved to glue in order to use OS-Specific
0077      * solutions
0078      */
0079     return crc_ccitt(chks, buf, len);
0080 }
0081 
0082 static int cffrml_receive(struct cflayer *layr, struct cfpkt *pkt)
0083 {
0084     u16 tmp;
0085     u16 len;
0086     u16 hdrchks;
0087     int pktchks;
0088     struct cffrml *this;
0089     this = container_obj(layr);
0090 
0091     cfpkt_extr_head(pkt, &tmp, 2);
0092     len = le16_to_cpu(tmp);
0093 
0094     /* Subtract for FCS on length if FCS is not used. */
0095     if (!this->dofcs)
0096         len -= 2;
0097 
0098     if (cfpkt_setlen(pkt, len) < 0) {
0099         ++cffrml_rcv_error;
0100         pr_err("Framing length error (%d)\n", len);
0101         cfpkt_destroy(pkt);
0102         return -EPROTO;
0103     }
0104     /*
0105      * Don't do extract if FCS is false, rather do setlen - then we don't
0106      * get a cache-miss.
0107      */
0108     if (this->dofcs) {
0109         cfpkt_extr_trail(pkt, &tmp, 2);
0110         hdrchks = le16_to_cpu(tmp);
0111         pktchks = cfpkt_iterate(pkt, cffrml_checksum, 0xffff);
0112         if (pktchks != hdrchks) {
0113             cfpkt_add_trail(pkt, &tmp, 2);
0114             ++cffrml_rcv_error;
0115             ++cffrml_rcv_checsum_error;
0116             pr_info("Frame checksum error (0x%x != 0x%x)\n",
0117                 hdrchks, pktchks);
0118             return -EILSEQ;
0119         }
0120     }
0121     if (cfpkt_erroneous(pkt)) {
0122         ++cffrml_rcv_error;
0123         pr_err("Packet is erroneous!\n");
0124         cfpkt_destroy(pkt);
0125         return -EPROTO;
0126     }
0127 
0128     if (layr->up == NULL) {
0129         pr_err("Layr up is missing!\n");
0130         cfpkt_destroy(pkt);
0131         return -EINVAL;
0132     }
0133 
0134     return layr->up->receive(layr->up, pkt);
0135 }
0136 
0137 static int cffrml_transmit(struct cflayer *layr, struct cfpkt *pkt)
0138 {
0139     u16 chks;
0140     u16 len;
0141     __le16 data;
0142 
0143     struct cffrml *this = container_obj(layr);
0144     if (this->dofcs) {
0145         chks = cfpkt_iterate(pkt, cffrml_checksum, 0xffff);
0146         data = cpu_to_le16(chks);
0147         cfpkt_add_trail(pkt, &data, 2);
0148     } else {
0149         cfpkt_pad_trail(pkt, 2);
0150     }
0151     len = cfpkt_getlen(pkt);
0152     data = cpu_to_le16(len);
0153     cfpkt_add_head(pkt, &data, 2);
0154     cfpkt_info(pkt)->hdr_len += 2;
0155     if (cfpkt_erroneous(pkt)) {
0156         pr_err("Packet is erroneous!\n");
0157         cfpkt_destroy(pkt);
0158         return -EPROTO;
0159     }
0160 
0161     if (layr->dn == NULL) {
0162         cfpkt_destroy(pkt);
0163         return -ENODEV;
0164 
0165     }
0166     return layr->dn->transmit(layr->dn, pkt);
0167 }
0168 
0169 static void cffrml_ctrlcmd(struct cflayer *layr, enum caif_ctrlcmd ctrl,
0170                int phyid)
0171 {
0172     if (layr->up && layr->up->ctrlcmd)
0173         layr->up->ctrlcmd(layr->up, ctrl, layr->id);
0174 }
0175 
0176 void cffrml_put(struct cflayer *layr)
0177 {
0178     struct cffrml *this = container_obj(layr);
0179     if (layr != NULL && this->pcpu_refcnt != NULL)
0180         this_cpu_dec(*this->pcpu_refcnt);
0181 }
0182 
0183 void cffrml_hold(struct cflayer *layr)
0184 {
0185     struct cffrml *this = container_obj(layr);
0186     if (layr != NULL && this->pcpu_refcnt != NULL)
0187         this_cpu_inc(*this->pcpu_refcnt);
0188 }
0189 
0190 int cffrml_refcnt_read(struct cflayer *layr)
0191 {
0192     int i, refcnt = 0;
0193     struct cffrml *this = container_obj(layr);
0194     for_each_possible_cpu(i)
0195         refcnt += *per_cpu_ptr(this->pcpu_refcnt, i);
0196     return refcnt;
0197 }