Skip to content

Commit 9428064

Browse files
committed
Enable SPPP core to handle multiple client tx.
This is done with a kfifo of 'active' messages that is regularly cleared and sent to the STM using a kfifo. Introduces a new SPPP API.
1 parent 6848e97 commit 9428064

File tree

7 files changed

+338
-136
lines changed

7 files changed

+338
-136
lines changed

arch/arm/mach-mx5/Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ obj-$(CONFIG_MACH_MX53_EVK) += board-mx53_evk.o
1717
obj-$(CONFIG_MACH_MX53_SMD) += board-mx53_smd.o mx53_smd_pmic_da9053.o
1818
obj-$(CONFIG_MACH_IMX_BLUETOOTH_RFKILL) += imx_bt_rfkill.o
1919
obj-$(CONFIG_MACH_MX53_LOCO) += board-mx53_loco.o mx53_loco_pmic_da9053.o
20-
obj-$(CONFIG_MACH_MX53_EFIKASB) += board-mx53_efikasb.o spppdriver.o
20+
obj-$(CONFIG_MACH_MX53_EFIKASB) += board-mx53_efikasb.o sppp_priv.o spppdriver.o
2121
obj-$(CONFIG_MACH_MX53_ARD) += board-mx53_ard.o
2222
obj-$(CONFIG_MACH_EUKREA_CPUIMX51) += board-cpuimx51.o
2323
obj-$(CONFIG_MACH_EUKREA_MBIMX51_BASEBOARD) += eukrea_mbimx51-baseboard.o

arch/arm/mach-mx5/sppp_priv.c

Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,147 @@
1+
#include <linux/kernel.h>
2+
#include <linux/kfifo.h>
3+
#include <linux/delay.h>
4+
#include <linux/workqueue.h>
5+
#include <linux/spinlock.h>
6+
#include <linux/spinlock_types.h>
7+
8+
#include <linux/sppp.h>
9+
#include "sppp_priv.h"
10+
11+
#define MAX_ACTIVE_MSGS (2*MAX_PKG_SIZE)
12+
static DEFINE_KFIFO(sppp_active_msgs, uint8_t, MAX_ACTIVE_MSGS);
13+
static DEFINE_SPINLOCK(sppp_active_msgs_spinlock);
14+
static struct workqueue_struct *msgs_wqueue;
15+
static struct delayed_work msgs_work;
16+
17+
/*
18+
* sppp_msgs - code for handling concurrent SPPP messages from
19+
* multiple sources
20+
*/
21+
22+
/* helper functions to track length of messages */
23+
24+
static inline void enqueue_len_for_active_msg(const int msg_len)
25+
{
26+
uint8_t tmp;
27+
28+
tmp = (uint8_t)msg_len;
29+
kfifo_put(&sppp_active_msgs, &tmp);
30+
31+
tmp = (uint8_t)(msg_len >> 8);
32+
kfifo_put(&sppp_active_msgs, &tmp);
33+
}
34+
35+
static inline int dequeue_len_for_active_msg(int *msg_len)
36+
{
37+
uint8_t tmp = 0;
38+
int ret;
39+
40+
ret = kfifo_get(&sppp_active_msgs, &tmp);
41+
*msg_len = tmp;
42+
43+
ret &= kfifo_get(&sppp_active_msgs, &tmp);
44+
*msg_len |= ((uint16_t)tmp) << 8;
45+
46+
return ret;
47+
}
48+
49+
static void sppp_msgs_hard_reset(sppp_tx_t *sppp_tx)
50+
{
51+
unsigned long flags;
52+
53+
spin_lock_irqsave(&sppp_active_msgs_spinlock, flags);
54+
55+
kfifo_reset(&sppp_active_msgs);
56+
sppp_stop(sppp_tx); /* whatever we were doing, stop */
57+
58+
spin_unlock_irqrestore(&sppp_active_msgs_spinlock, flags);
59+
}
60+
61+
/* function to send periodically the accumulated messages to STM */
62+
void sppp_msgs_work(struct work_struct *work)
63+
{
64+
const int interval = 1 * HZ;
65+
uint8_t tmp = 0;
66+
int msg_len = 0;
67+
sppp_tx_t sppp_tx;
68+
69+
/* boilerplate */
70+
#define KFIFO_GET_GUARDED(kfifo_get_exp) \
71+
if ((kfifo_get_exp) != 1) { \
72+
printk(KERN_ERR "fatal error in SPPP TX\n"); \
73+
sppp_msgs_hard_reset(&sppp_tx); \
74+
goto out; \
75+
}
76+
77+
#define KFIFO_GET_MSG() \
78+
KFIFO_GET_GUARDED(kfifo_get(&sppp_active_msgs, &tmp)); \
79+
--msg_len;
80+
81+
while (kfifo_len(&sppp_active_msgs) > 0) {
82+
KFIFO_GET_GUARDED(dequeue_len_for_active_msg(&msg_len));
83+
84+
KFIFO_GET_MSG();
85+
sppp_start(&sppp_tx, tmp);
86+
87+
while (msg_len > 0) {
88+
KFIFO_GET_MSG();
89+
sppp_data(&sppp_tx, tmp);
90+
}
91+
92+
sppp_stop(&sppp_tx);
93+
}
94+
95+
out:
96+
queue_delayed_work(msgs_wqueue, &msgs_work, interval);
97+
}
98+
99+
/* enqueue a complete message for the STM without interruption */
100+
void sppp_msgs_set_active(struct kfifo *cl_fifo)
101+
{
102+
unsigned long flags;
103+
const int cl_len = kfifo_len(cl_fifo);
104+
uint8_t tmp;
105+
106+
spin_lock_irqsave(&sppp_active_msgs_spinlock, flags);
107+
108+
/* TODO magic number */
109+
if (kfifo_len(&sppp_active_msgs) + cl_len + 2 >
110+
MAX_ACTIVE_MSGS) {
111+
printk(KERN_ERR "too much traffic to STM!");
112+
goto out;
113+
}
114+
115+
enqueue_len_for_active_msg(cl_len);
116+
while (kfifo_get(cl_fifo, &tmp)) {
117+
kfifo_put(&sppp_active_msgs, &tmp);
118+
}
119+
120+
out:
121+
spin_unlock_irqrestore(&sppp_active_msgs_spinlock, flags);
122+
}
123+
124+
int sppp_priv_init()
125+
{
126+
int retval = 0;
127+
128+
INIT_DELAYED_WORK(&msgs_work, sppp_msgs_work);
129+
msgs_wqueue = create_singlethread_workqueue("sppp_core_driver");
130+
if (!msgs_wqueue) {
131+
retval = -ESRCH;
132+
goto workqueue_failed;
133+
}
134+
queue_delayed_work(msgs_wqueue, &msgs_work, 1 * HZ);
135+
return 0;
136+
137+
workqueue_failed:
138+
printk(KERN_ERR "%s unable to create workqueue for STM messages",
139+
__func__);
140+
return retval;
141+
}
142+
143+
void sppp_priv_exit()
144+
{
145+
cancel_delayed_work_sync(&msgs_work);
146+
destroy_workqueue(msgs_wqueue);
147+
}

arch/arm/mach-mx5/sppp_priv.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
#include <linux/kernel.h>
2+
#include <linux/kfifo.h>
3+
#include <linux/delay.h>
4+
#include <linux/workqueue.h>
5+
6+
#include <linux/sppp.h>
7+
8+
void sppp_msgs_work(struct work_struct *);
9+
10+
void sppp_msgs_set_active(struct kfifo *);
11+
12+
int sppp_priv_init(void);
13+
void sppp_priv_exit(void);

0 commit comments

Comments
 (0)