Skip to content

Commit

Permalink
big bugfix to csma layer. holy moly!
Browse files Browse the repository at this point in the history
  • Loading branch information
anroOfCode committed Jan 15, 2013
1 parent 56a536f commit 9a523e8
Show file tree
Hide file tree
Showing 8 changed files with 146 additions and 94 deletions.
4 changes: 2 additions & 2 deletions cc2520.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,8 @@
#define CC2520_GPIO_5 -1
#define CC2520_RESET 17

#define CC2520_DEBUG_0 21
#define CC2520_DEBUG_1 18
#define CC2520_DEBUG_0 4
#define CC2520_DEBUG_1 3

// Logical mapping of CC2520 GPIO pins to
// functions, we're going to keep these static
Expand Down
61 changes: 46 additions & 15 deletions csma.c
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#include <linux/hrtimer.h>
#include <linux/spinlock.h>
#include <linux/random.h>
#include <linux/workqueue.h>

#include "csma.h"
#include "cc2520.h"
Expand All @@ -22,6 +23,9 @@ static u8 cur_tx_len;

static spinlock_t state_sl;

static struct workqueue_struct *wq;
static struct work_struct work;

enum cc2520_csma_state_enum {
CC2520_CSMA_IDLE,
CC2520_CSMA_TX,
Expand All @@ -30,12 +34,15 @@ enum cc2520_csma_state_enum {

static int csma_state;

static unsigned long flags;

static int cc2520_csma_tx(u8 * buf, u8 len);
static void cc2520_csma_tx_done(u8 status);
static void cc2520_csma_rx_done(u8 *buf, u8 len);
static enum hrtimer_restart cc2520_csma_timer_cb(struct hrtimer *timer);
static void cc2520_csma_start_timer(int us_period);
static int cc2520_csma_get_backoff(int min, int max);
static void cc2520_csma_wq(struct work_struct *work);

int cc2520_csma_init()
{
Expand All @@ -55,6 +62,11 @@ int cc2520_csma_init()
goto error;
}

wq = alloc_workqueue("csma_wq", WQ_HIGHPRI, 128);
if (!wq) {
goto error;
}

hrtimer_init(&backoff_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
backoff_timer.function = &cc2520_csma_timer_cb;

Expand All @@ -66,6 +78,10 @@ int cc2520_csma_init()
cur_tx_buf = NULL;
}

if (wq) {
destroy_workqueue(wq);
}

return -EFAULT;
}

Expand All @@ -76,6 +92,10 @@ void cc2520_csma_free()
cur_tx_buf = NULL;
}

if (wq) {
destroy_workqueue(wq);
}

hrtimer_cancel(&backoff_timer);
}

Expand All @@ -101,56 +121,67 @@ static enum hrtimer_restart cc2520_csma_timer_cb(struct hrtimer *timer)
ktime_t kt;
int new_backoff;

//printk(KERN_INFO "[cc2520] - csma timer fired. \n");
if (cc2520_radio_is_clear()) {
//printk(KERN_INFO "[cc2520] - channel clear, sending.\n");
csma_bottom->tx(cur_tx_buf, cur_tx_len);
// NOTE: We can absolutely not send from
// interrupt context, there's a few places
// where we spin lock and assume we can be
// preempted. If we're running in atomic mode
// that promise is broken. We use a work queue.

// The workqueue adds about 30uS of latency.
INIT_WORK(&work, cc2520_csma_wq);
queue_work(wq, &work);
return HRTIMER_NORESTART;
}
else {
spin_lock(&state_sl);
spin_lock_irqsave(&state_sl, flags);
if (csma_state == CC2520_CSMA_TX) {
csma_state = CC2520_CSMA_CONG;
spin_unlock(&state_sl);
spin_unlock_irqrestore(&state_sl, flags);

new_backoff =
cc2520_csma_get_backoff(backoff_min, backoff_max_cong);

INFO((KERN_INFO "[cc2520] - channel still busy, waiting %d uS\n", new_backoff));
kt=ktime_set(0,1000 * new_backoff);
kt = ktime_set(0,1000 * new_backoff);
hrtimer_forward_now(&backoff_timer, kt);
return HRTIMER_RESTART;
}
else {
csma_state = CC2520_CSMA_IDLE;
spin_unlock(&state_sl);
spin_unlock_irqrestore(&state_sl, flags);

INFO((KERN_INFO "[cc2520] - csma/ca: channel busy. aborting tx\n"));
csma_top->tx_done(-CC2520_TX_BUSY);
return HRTIMER_NORESTART;
}
}
}

static void cc2520_csma_wq(struct work_struct *work)
{
csma_bottom->tx(cur_tx_buf, cur_tx_len);
}

static int cc2520_csma_tx(u8 * buf, u8 len)
{
int backoff;

spin_lock(&state_sl);
spin_lock_irqsave(&state_sl, flags);
if (csma_state == CC2520_CSMA_IDLE) {
csma_state = CC2520_CSMA_TX;
spin_unlock(&state_sl);
spin_unlock_irqrestore(&state_sl, flags);

memcpy(cur_tx_buf, buf, len);
cur_tx_len = len;

backoff = cc2520_csma_get_backoff(backoff_min, backoff_max_init);

//printk(KERN_INFO "[cc2520] - waiting %d uS to send.\n", backoff);
DBG((KERN_INFO "[cc2520] - waiting %d uS to send.\n", backoff));
cc2520_csma_start_timer(backoff);
}
else {
spin_unlock(&state_sl);
spin_unlock_irqrestore(&state_sl, flags);
DBG((KERN_INFO "[cc2520] - csma layer busy.\n"));
csma_top->tx_done(-CC2520_TX_BUSY);
}

Expand All @@ -159,10 +190,10 @@ static int cc2520_csma_tx(u8 * buf, u8 len)

static void cc2520_csma_tx_done(u8 status)
{
spin_lock(&state_sl);
spin_lock_irqsave(&state_sl, flags);
csma_state = CC2520_CSMA_IDLE;
spin_unlock(&state_sl);
//printk(KERN_INFO "[cc2520] - tx done and successful.\n");
spin_unlock_irqrestore(&state_sl, flags);

csma_top->tx_done(status);
}

Expand Down
4 changes: 0 additions & 4 deletions interface.c
Original file line number Diff line number Diff line change
Expand Up @@ -106,15 +106,11 @@ static ssize_t interface_write(
// the form of a semaphore.
interface_bottom->tx(tx_buf_c, pkt_len);
down(&tx_done_sem);
//if (result) {
// return -ERESTARTSYS;
//}

// Step 4: Finally return and allow other callers to write
// packets.
DBG((KERN_INFO "[cc2520] - wrote %d bytes.\n", pkt_len));
up(&tx_sem);

return tx_result ? tx_result : pkt_len;

error:
Expand Down
27 changes: 15 additions & 12 deletions lpl.c
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ static u8 cur_tx_len;

static spinlock_t state_sl;

static unsigned long flags;

enum cc2520_lpl_state_enum {
CC2520_LPL_IDLE,
CC2520_LPL_TX,
Expand Down Expand Up @@ -80,10 +82,10 @@ void cc2520_lpl_free()
static int cc2520_lpl_tx(u8 * buf, u8 len)
{
if (lpl_enabled) {
spin_lock(&state_sl);
spin_lock_irqsave(&state_sl, flags);
if (lpl_state == CC2520_LPL_IDLE) {
lpl_state = CC2520_LPL_TX;
spin_unlock(&state_sl);
spin_unlock_irqrestore(&state_sl, flags);

memcpy(cur_tx_buf, buf, len);
cur_tx_len = len;
Expand All @@ -92,7 +94,8 @@ static int cc2520_lpl_tx(u8 * buf, u8 len)
cc2520_lpl_start_timer();
}
else {
spin_unlock(&state_sl);
spin_unlock_irqrestore(&state_sl, flags);
INFO(("[cc2520] - lpl tx busy.\n"));
lpl_top->tx_done(-CC2520_TX_BUSY);
}

Expand All @@ -106,34 +109,34 @@ static int cc2520_lpl_tx(u8 * buf, u8 len)
static void cc2520_lpl_tx_done(u8 status)
{
if (lpl_enabled) {
spin_lock(&state_sl);
spin_lock_irqsave(&state_sl, flags);
if (cc2520_packet_requires_ack_wait(cur_tx_buf)) {
if (status == CC2520_TX_SUCCESS) {
lpl_state = CC2520_LPL_IDLE;
spin_unlock(&state_sl);
spin_unlock_irqrestore(&state_sl, flags);

hrtimer_cancel(&lpl_timer);
lpl_top->tx_done(status);
}
else if (lpl_state == CC2520_LPL_TIMER_EXPIRED) {
lpl_state = CC2520_LPL_IDLE;
spin_unlock(&state_sl);
spin_unlock_irqrestore(&state_sl, flags);
lpl_top->tx_done(-CC2520_TX_FAILED);
}
else {
spin_unlock(&state_sl);
spin_unlock_irqrestore(&state_sl, flags);
//printk(KERN_INFO "[cc2520] - lpl retransmit.\n");
lpl_bottom->tx(cur_tx_buf, cur_tx_len);
}
}
else {
if (lpl_state == CC2520_LPL_TIMER_EXPIRED) {
lpl_state = CC2520_LPL_IDLE;
spin_unlock(&state_sl);
spin_unlock_irqrestore(&state_sl, flags);
lpl_top->tx_done(CC2520_TX_SUCCESS);
}
else {
spin_unlock(&state_sl);
spin_unlock_irqrestore(&state_sl, flags);
lpl_bottom->tx(cur_tx_buf, cur_tx_len);
}
}
Expand Down Expand Up @@ -161,13 +164,13 @@ static void cc2520_lpl_start_timer()

static enum hrtimer_restart cc2520_lpl_timer_cb(struct hrtimer *timer)
{
spin_lock(&state_sl);
spin_lock_irqsave(&state_sl, flags);
if (lpl_state == CC2520_LPL_TX) {
lpl_state = CC2520_LPL_TIMER_EXPIRED;
spin_unlock(&state_sl);
spin_unlock_irqrestore(&state_sl, flags);
}
else {
spin_unlock(&state_sl);
spin_unlock_irqrestore(&state_sl, flags);
INFO((KERN_INFO "[cc2520] - lpl timer in improbable state.\n"));
}

Expand Down
3 changes: 1 addition & 2 deletions platform.c
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,7 @@ static irqreturn_t cc2520_sfd_handler(int irq, void *dev_id)
nanos = timespec_to_ns(&ts);
gpio_val = gpio_get_value(CC2520_SFD);

DBG((KERN_INFO "[cc2520] - sfd interrupt occurred at %lld, %d\n", (long long int)nanos, gpio_val));
//DBG((KERN_INFO "[cc2520] - sfd interrupt occurred at %lld, %d\n", (long long int)nanos, gpio_val));

cc2520_radio_sfd_occurred(nanos, gpio_val);
return IRQ_HANDLED;
Expand Down Expand Up @@ -207,7 +207,6 @@ int cc2520_plat_gpio_init()
goto fail;

gpio_set_value(CC2520_DEBUG_0, 0);
gpio_set_value(CC2520_DEBUG_1, 0);

// Setup FIFOP Interrupt
irq = gpio_to_irq(CC2520_FIFOP);
Expand Down
Loading

0 comments on commit 9a523e8

Please sign in to comment.