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