1 /* 2 * CAIF Framing Layer. 3 * 4 * Copyright (C) ST-Ericsson AB 2010 5 * Author: Sjur Brendeland/sjur.brandeland@stericsson.com 6 * License terms: GNU General Public License (GPL) version 2 7 */ 8 9 #define pr_fmt(fmt) KBUILD_MODNAME ":%s(): " fmt, __func__ 10 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> 19 20 #define container_obj(layr) container_of(layr, struct cffrml, layer) 21 22 struct cffrml { 23 struct cflayer layer; 24 bool dofcs; /* !< FCS active */ 25 int __percpu *pcpu_refcnt; 26 }; 27 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, 31 int phyid); 32 33 static u32 cffrml_rcv_error; 34 static u32 cffrml_rcv_checsum_error; 35 struct cflayer *cffrml_create(u16 phyid, bool use_fcs) 36 { 37 struct cffrml *this = kmalloc(sizeof(struct cffrml), GFP_ATOMIC); 38 if (!this) { 39 pr_warn("Out of memory\n"); 40 return NULL; 41 } 42 this->pcpu_refcnt = alloc_percpu(int); 43 if (this->pcpu_refcnt == NULL) { 44 kfree(this); 45 return NULL; 46 } 47 48 caif_assert(offsetof(struct cffrml, layer) == 0); 49 50 memset(this, 0, sizeof(struct cflayer)); 51 this->layer.receive = cffrml_receive; 52 this->layer.transmit = cffrml_transmit; 53 this->layer.ctrlcmd = cffrml_ctrlcmd; 54 snprintf(this->layer.name, CAIF_LAYER_NAME_SZ, "frm%d", phyid); 55 this->dofcs = use_fcs; 56 this->layer.id = phyid; 57 return (struct cflayer *) this; 58 } 59 60 void cffrml_free(struct cflayer *layer) 61 { 62 struct cffrml *this = container_obj(layer); 63 free_percpu(this->pcpu_refcnt); 64 kfree(layer); 65 } 66 67 void cffrml_set_uplayer(struct cflayer *this, struct cflayer *up) 68 { 69 this->up = up; 70 } 71 72 void cffrml_set_dnlayer(struct cflayer *this, struct cflayer *dn) 73 { 74 this->dn = dn; 75 } 76 77 static u16 cffrml_checksum(u16 chks, void *buf, u16 len) 78 { 79 /* FIXME: FCS should be moved to glue in order to use OS-Specific 80 * solutions 81 */ 82 return crc_ccitt(chks, buf, len); 83 } 84 85 static int cffrml_receive(struct cflayer *layr, struct cfpkt *pkt) 86 { 87 u16 tmp; 88 u16 len; 89 u16 hdrchks; 90 u16 pktchks; 91 struct cffrml *this; 92 this = container_obj(layr); 93 94 cfpkt_extr_head(pkt, &tmp, 2); 95 len = le16_to_cpu(tmp); 96 97 /* Subtract for FCS on length if FCS is not used. */ 98 if (!this->dofcs) 99 len -= 2; 100 101 if (cfpkt_setlen(pkt, len) < 0) { 102 ++cffrml_rcv_error; 103 pr_err("Framing length error (%d)\n", len); 104 cfpkt_destroy(pkt); 105 return -EPROTO; 106 } 107 /* 108 * Don't do extract if FCS is false, rather do setlen - then we don't 109 * get a cache-miss. 110 */ 111 if (this->dofcs) { 112 cfpkt_extr_trail(pkt, &tmp, 2); 113 hdrchks = le16_to_cpu(tmp); 114 pktchks = cfpkt_iterate(pkt, cffrml_checksum, 0xffff); 115 if (pktchks != hdrchks) { 116 cfpkt_add_trail(pkt, &tmp, 2); 117 ++cffrml_rcv_error; 118 ++cffrml_rcv_checsum_error; 119 pr_info("Frame checksum error (0x%x != 0x%x)\n", 120 hdrchks, pktchks); 121 return -EILSEQ; 122 } 123 } 124 if (cfpkt_erroneous(pkt)) { 125 ++cffrml_rcv_error; 126 pr_err("Packet is erroneous!\n"); 127 cfpkt_destroy(pkt); 128 return -EPROTO; 129 } 130 131 if (layr->up == NULL) { 132 pr_err("Layr up is missing!\n"); 133 cfpkt_destroy(pkt); 134 return -EINVAL; 135 } 136 137 return layr->up->receive(layr->up, pkt); 138 } 139 140 static int cffrml_transmit(struct cflayer *layr, struct cfpkt *pkt) 141 { 142 int tmp; 143 u16 chks; 144 u16 len; 145 struct cffrml *this = container_obj(layr); 146 if (this->dofcs) { 147 chks = cfpkt_iterate(pkt, cffrml_checksum, 0xffff); 148 tmp = cpu_to_le16(chks); 149 cfpkt_add_trail(pkt, &tmp, 2); 150 } else { 151 cfpkt_pad_trail(pkt, 2); 152 } 153 len = cfpkt_getlen(pkt); 154 tmp = cpu_to_le16(len); 155 cfpkt_add_head(pkt, &tmp, 2); 156 cfpkt_info(pkt)->hdr_len += 2; 157 if (cfpkt_erroneous(pkt)) { 158 pr_err("Packet is erroneous!\n"); 159 cfpkt_destroy(pkt); 160 return -EPROTO; 161 } 162 163 if (layr->dn == NULL) { 164 cfpkt_destroy(pkt); 165 return -ENODEV; 166 167 } 168 return layr->dn->transmit(layr->dn, pkt); 169 } 170 171 static void cffrml_ctrlcmd(struct cflayer *layr, enum caif_ctrlcmd ctrl, 172 int phyid) 173 { 174 if (layr->up && layr->up->ctrlcmd) 175 layr->up->ctrlcmd(layr->up, ctrl, layr->id); 176 } 177 178 void cffrml_put(struct cflayer *layr) 179 { 180 struct cffrml *this = container_obj(layr); 181 if (layr != NULL && this->pcpu_refcnt != NULL) 182 irqsafe_cpu_dec(*this->pcpu_refcnt); 183 } 184 185 void cffrml_hold(struct cflayer *layr) 186 { 187 struct cffrml *this = container_obj(layr); 188 if (layr != NULL && this->pcpu_refcnt != NULL) 189 irqsafe_cpu_inc(*this->pcpu_refcnt); 190 } 191 192 int cffrml_refcnt_read(struct cflayer *layr) 193 { 194 int i, refcnt = 0; 195 struct cffrml *this = container_obj(layr); 196 for_each_possible_cpu(i) 197 refcnt += *per_cpu_ptr(this->pcpu_refcnt, i); 198 return refcnt; 199 } 200