Blame view

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