1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Copyright (C) ST-Ericsson AB 2010 4 * Author: Sjur Brendeland 5 */ 6 7 #define pr_fmt(fmt) KBUILD_MODNAME ":%s(): " fmt, __func__ 8 9 #include <linux/stddef.h> 10 #include <linux/spinlock.h> 11 #include <linux/slab.h> 12 #include <net/caif/caif_layer.h> 13 #include <net/caif/cfpkt.h> 14 #include <net/caif/cfserl.h> 15 16 #define container_obj(layr) ((struct cfserl *) layr) 17 18 #define CFSERL_STX 0x02 19 #define SERIAL_MINIUM_PACKET_SIZE 4 20 #define SERIAL_MAX_FRAMESIZE 4096 21 struct cfserl { 22 struct cflayer layer; 23 struct cfpkt *incomplete_frm; 24 /* Protects parallel processing of incoming packets */ 25 spinlock_t sync; 26 bool usestx; 27 }; 28 29 static int cfserl_receive(struct cflayer *layr, struct cfpkt *pkt); 30 static int cfserl_transmit(struct cflayer *layr, struct cfpkt *pkt); 31 static void cfserl_ctrlcmd(struct cflayer *layr, enum caif_ctrlcmd ctrl, 32 int phyid); 33 34 void cfserl_release(struct cflayer *layer) 35 { 36 kfree(layer); 37 } 38 39 struct cflayer *cfserl_create(int instance, bool use_stx) 40 { 41 struct cfserl *this = kzalloc(sizeof(struct cfserl), GFP_ATOMIC); 42 if (!this) 43 return NULL; 44 caif_assert(offsetof(struct cfserl, layer) == 0); 45 this->layer.receive = cfserl_receive; 46 this->layer.transmit = cfserl_transmit; 47 this->layer.ctrlcmd = cfserl_ctrlcmd; 48 this->usestx = use_stx; 49 spin_lock_init(&this->sync); 50 snprintf(this->layer.name, CAIF_LAYER_NAME_SZ, "ser1"); 51 return &this->layer; 52 } 53 54 static int cfserl_receive(struct cflayer *l, struct cfpkt *newpkt) 55 { 56 struct cfserl *layr = container_obj(l); 57 u16 pkt_len; 58 struct cfpkt *pkt = NULL; 59 struct cfpkt *tail_pkt = NULL; 60 u8 tmp8; 61 u16 tmp; 62 u8 stx = CFSERL_STX; 63 int ret; 64 u16 expectlen = 0; 65 66 caif_assert(newpkt != NULL); 67 spin_lock(&layr->sync); 68 69 if (layr->incomplete_frm != NULL) { 70 layr->incomplete_frm = 71 cfpkt_append(layr->incomplete_frm, newpkt, expectlen); 72 pkt = layr->incomplete_frm; 73 if (pkt == NULL) { 74 spin_unlock(&layr->sync); 75 return -ENOMEM; 76 } 77 } else { 78 pkt = newpkt; 79 } 80 layr->incomplete_frm = NULL; 81 82 do { 83 /* Search for STX at start of pkt if STX is used */ 84 if (layr->usestx) { 85 cfpkt_extr_head(pkt, &tmp8, 1); 86 if (tmp8 != CFSERL_STX) { 87 while (cfpkt_more(pkt) 88 && tmp8 != CFSERL_STX) { 89 cfpkt_extr_head(pkt, &tmp8, 1); 90 } 91 if (!cfpkt_more(pkt)) { 92 cfpkt_destroy(pkt); 93 layr->incomplete_frm = NULL; 94 spin_unlock(&layr->sync); 95 return -EPROTO; 96 } 97 } 98 } 99 100 pkt_len = cfpkt_getlen(pkt); 101 102 /* 103 * pkt_len is the accumulated length of the packet data 104 * we have received so far. 105 * Exit if frame doesn't hold length. 106 */ 107 108 if (pkt_len < 2) { 109 if (layr->usestx) 110 cfpkt_add_head(pkt, &stx, 1); 111 layr->incomplete_frm = pkt; 112 spin_unlock(&layr->sync); 113 return 0; 114 } 115 116 /* 117 * Find length of frame. 118 * expectlen is the length we need for a full frame. 119 */ 120 cfpkt_peek_head(pkt, &tmp, 2); 121 expectlen = le16_to_cpu(tmp) + 2; 122 /* 123 * Frame error handling 124 */ 125 if (expectlen < SERIAL_MINIUM_PACKET_SIZE 126 || expectlen > SERIAL_MAX_FRAMESIZE) { 127 if (!layr->usestx) { 128 if (pkt != NULL) 129 cfpkt_destroy(pkt); 130 layr->incomplete_frm = NULL; 131 expectlen = 0; 132 spin_unlock(&layr->sync); 133 return -EPROTO; 134 } 135 continue; 136 } 137 138 if (pkt_len < expectlen) { 139 /* Too little received data */ 140 if (layr->usestx) 141 cfpkt_add_head(pkt, &stx, 1); 142 layr->incomplete_frm = pkt; 143 spin_unlock(&layr->sync); 144 return 0; 145 } 146 147 /* 148 * Enough data for at least one frame. 149 * Split the frame, if too long 150 */ 151 if (pkt_len > expectlen) 152 tail_pkt = cfpkt_split(pkt, expectlen); 153 else 154 tail_pkt = NULL; 155 156 /* Send the first part of packet upwards.*/ 157 spin_unlock(&layr->sync); 158 ret = layr->layer.up->receive(layr->layer.up, pkt); 159 spin_lock(&layr->sync); 160 if (ret == -EILSEQ) { 161 if (layr->usestx) { 162 if (tail_pkt != NULL) 163 pkt = cfpkt_append(pkt, tail_pkt, 0); 164 /* Start search for next STX if frame failed */ 165 continue; 166 } else { 167 cfpkt_destroy(pkt); 168 pkt = NULL; 169 } 170 } 171 172 pkt = tail_pkt; 173 174 } while (pkt != NULL); 175 176 spin_unlock(&layr->sync); 177 return 0; 178 } 179 180 static int cfserl_transmit(struct cflayer *layer, struct cfpkt *newpkt) 181 { 182 struct cfserl *layr = container_obj(layer); 183 u8 tmp8 = CFSERL_STX; 184 if (layr->usestx) 185 cfpkt_add_head(newpkt, &tmp8, 1); 186 return layer->dn->transmit(layer->dn, newpkt); 187 } 188 189 static void cfserl_ctrlcmd(struct cflayer *layr, enum caif_ctrlcmd ctrl, 190 int phyid) 191 { 192 layr->up->ctrlcmd(layr->up, ctrl, phyid); 193 } 194