diff options
Diffstat (limited to 'net/caif/cffrml.c')
-rw-r--r-- | net/caif/cffrml.c | 60 |
1 files changed, 53 insertions, 7 deletions
diff --git a/net/caif/cffrml.c b/net/caif/cffrml.c index a445043931ae..04204b202718 100644 --- a/net/caif/cffrml.c +++ b/net/caif/cffrml.c | |||
@@ -12,6 +12,7 @@ | |||
12 | #include <linux/spinlock.h> | 12 | #include <linux/spinlock.h> |
13 | #include <linux/slab.h> | 13 | #include <linux/slab.h> |
14 | #include <linux/crc-ccitt.h> | 14 | #include <linux/crc-ccitt.h> |
15 | #include <linux/netdevice.h> | ||
15 | #include <net/caif/caif_layer.h> | 16 | #include <net/caif/caif_layer.h> |
16 | #include <net/caif/cfpkt.h> | 17 | #include <net/caif/cfpkt.h> |
17 | #include <net/caif/cffrml.h> | 18 | #include <net/caif/cffrml.h> |
@@ -21,6 +22,7 @@ | |||
21 | struct cffrml { | 22 | struct cffrml { |
22 | struct cflayer layer; | 23 | struct cflayer layer; |
23 | bool dofcs; /* !< FCS active */ | 24 | bool dofcs; /* !< FCS active */ |
25 | int __percpu *pcpu_refcnt; | ||
24 | }; | 26 | }; |
25 | 27 | ||
26 | static int cffrml_receive(struct cflayer *layr, struct cfpkt *pkt); | 28 | static int cffrml_receive(struct cflayer *layr, struct cfpkt *pkt); |
@@ -37,6 +39,12 @@ struct cflayer *cffrml_create(u16 phyid, bool use_fcs) | |||
37 | pr_warn("Out of memory\n"); | 39 | pr_warn("Out of memory\n"); |
38 | return NULL; | 40 | return NULL; |
39 | } | 41 | } |
42 | this->pcpu_refcnt = alloc_percpu(int); | ||
43 | if (this->pcpu_refcnt == NULL) { | ||
44 | kfree(this); | ||
45 | return NULL; | ||
46 | } | ||
47 | |||
40 | caif_assert(offsetof(struct cffrml, layer) == 0); | 48 | caif_assert(offsetof(struct cffrml, layer) == 0); |
41 | 49 | ||
42 | memset(this, 0, sizeof(struct cflayer)); | 50 | memset(this, 0, sizeof(struct cflayer)); |
@@ -49,6 +57,13 @@ struct cflayer *cffrml_create(u16 phyid, bool use_fcs) | |||
49 | return (struct cflayer *) this; | 57 | return (struct cflayer *) this; |
50 | } | 58 | } |
51 | 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 | |||
52 | void cffrml_set_uplayer(struct cflayer *this, struct cflayer *up) | 67 | void cffrml_set_uplayer(struct cflayer *this, struct cflayer *up) |
53 | { | 68 | { |
54 | this->up = up; | 69 | this->up = up; |
@@ -112,6 +127,13 @@ static int cffrml_receive(struct cflayer *layr, struct cfpkt *pkt) | |||
112 | cfpkt_destroy(pkt); | 127 | cfpkt_destroy(pkt); |
113 | return -EPROTO; | 128 | return -EPROTO; |
114 | } | 129 | } |
130 | |||
131 | if (layr->up == NULL) { | ||
132 | pr_err("Layr up is missing!\n"); | ||
133 | cfpkt_destroy(pkt); | ||
134 | return -EINVAL; | ||
135 | } | ||
136 | |||
115 | return layr->up->receive(layr->up, pkt); | 137 | return layr->up->receive(layr->up, pkt); |
116 | } | 138 | } |
117 | 139 | ||
@@ -120,7 +142,6 @@ static int cffrml_transmit(struct cflayer *layr, struct cfpkt *pkt) | |||
120 | int tmp; | 142 | int tmp; |
121 | u16 chks; | 143 | u16 chks; |
122 | u16 len; | 144 | u16 len; |
123 | int ret; | ||
124 | struct cffrml *this = container_obj(layr); | 145 | struct cffrml *this = container_obj(layr); |
125 | if (this->dofcs) { | 146 | if (this->dofcs) { |
126 | chks = cfpkt_iterate(pkt, cffrml_checksum, 0xffff); | 147 | chks = cfpkt_iterate(pkt, cffrml_checksum, 0xffff); |
@@ -135,19 +156,44 @@ static int cffrml_transmit(struct cflayer *layr, struct cfpkt *pkt) | |||
135 | cfpkt_info(pkt)->hdr_len += 2; | 156 | cfpkt_info(pkt)->hdr_len += 2; |
136 | if (cfpkt_erroneous(pkt)) { | 157 | if (cfpkt_erroneous(pkt)) { |
137 | pr_err("Packet is erroneous!\n"); | 158 | pr_err("Packet is erroneous!\n"); |
159 | cfpkt_destroy(pkt); | ||
138 | return -EPROTO; | 160 | return -EPROTO; |
139 | } | 161 | } |
140 | ret = layr->dn->transmit(layr->dn, pkt); | 162 | |
141 | if (ret < 0) { | 163 | if (layr->dn == NULL) { |
142 | /* Remove header on faulty packet. */ | 164 | cfpkt_destroy(pkt); |
143 | cfpkt_extr_head(pkt, &tmp, 2); | 165 | return -ENODEV; |
166 | |||
144 | } | 167 | } |
145 | return ret; | 168 | return layr->dn->transmit(layr->dn, pkt); |
146 | } | 169 | } |
147 | 170 | ||
148 | static void cffrml_ctrlcmd(struct cflayer *layr, enum caif_ctrlcmd ctrl, | 171 | static void cffrml_ctrlcmd(struct cflayer *layr, enum caif_ctrlcmd ctrl, |
149 | int phyid) | 172 | int phyid) |
150 | { | 173 | { |
151 | if (layr->up->ctrlcmd) | 174 | if (layr->up && layr->up->ctrlcmd) |
152 | layr->up->ctrlcmd(layr->up, ctrl, layr->id); | 175 | layr->up->ctrlcmd(layr->up, ctrl, layr->id); |
153 | } | 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 | } | ||