#define SLF_RXEVENT 2 /* Rx wake event */
#define SLF_TXEVENT 3 /* Tx wake event */
#define SLF_MSGEVENT 4 /* CAN message to sent */
-#define SLF_TMOUTEVENT 5 /* Timeout on received data */
+#define SLF_TMOUTEVENT 5 /* Timeout on received data */
+#define SLF_TXBUFF_RQ 6 /* Req. to send buffer to UART*/
+#define SLF_TXBUFF_INPR 7 /* Above request in progress */
dev_t line;
struct task_struct *kwthread;
/* List with configurations for each of 0 to LIN_ID_MAX LIN IDs */
struct sllin_conf_entry linfr_cache[LIN_ID_MAX + 1];
+ spinlock_t linfr_lock; /* frame cache and buffers lock */
};
static struct net_device **sllin_devs;
cf.can_id = id;
cf.can_dlc = len;
- if (cf.can_dlc > 0) {
+ if (cf.can_dlc > 0)
memcpy(&cf.data, data, cf.can_dlc);
- }
skb = dev_alloc_skb(sizeof(struct can_frame));
if (!skb)
*/
static void sllin_write_wakeup(struct tty_struct *tty)
{
- int actual;
+ int actual = 0;
int remains;
struct sllin *sl = (struct sllin *) tty->disc_data;
if (!sl || sl->magic != SLLIN_MAGIC || !netif_running(sl->dev))
return;
- if (sl->lin_state != SLSTATE_BREAK_SENT)
- remains = sl->tx_lim - sl->tx_cnt;
- else
- remains = SLLIN_BUFF_BREAK + 1 - sl->tx_cnt;
-
- if (remains > 0) {
- actual = tty->ops->write(tty, sl->tx_buff + sl->tx_cnt,
- sl->tx_cnt - sl->tx_lim);
- sl->tx_cnt += actual;
-
- if (sl->tx_cnt < sl->tx_lim) {
- pr_debug("sllin: sllin_write_wakeup sent %d, "
- "remains %d, waiting\n",
- sl->tx_cnt, sl->tx_lim - sl->tx_cnt);
- return;
+ set_bit(SLF_TXBUFF_RQ, &sl->flags);
+ do {
+ if (unlikely(test_and_set_bit(SLF_TXBUFF_INPR, &sl->flags)))
+ return; /* ongoing concurrent processing */
+
+ clear_bit(SLF_TXBUFF_RQ, &sl->flags);
+ smp_mb__after_clear_bit();
+
+ if (sl->lin_state != SLSTATE_BREAK_SENT)
+ remains = sl->tx_lim - sl->tx_cnt;
+ else
+ remains = SLLIN_BUFF_BREAK + 1 - sl->tx_cnt;
+
+ if (remains > 0) {
+ actual = tty->ops->write(tty, sl->tx_buff + sl->tx_cnt,
+ sl->tx_cnt - sl->tx_lim);
+ sl->tx_cnt += actual;
+ remains -= actual;
}
+ clear_bit(SLF_TXBUFF_INPR, &sl->flags);
+ smp_mb__after_clear_bit();
+
+ } while (unlikely(test_bit(SLF_TXBUFF_RQ, &sl->flags)));
+
+ if ((remains > 0) && (actual >= 0)) {
+ pr_debug("sllin: sllin_write_wakeup sent %d, "
+ "remains %d, waiting\n",
+ sl->tx_cnt, sl->tx_lim - sl->tx_cnt);
+ return;
}
clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
goto err_out_unlock;
}
if (sl->tty == NULL) {
+ printk(KERN_WARNING "%s: xmit: no tty device connected\n", dev->name);
goto err_out_unlock;
}
{
struct sllin *sl = netdev_priv(dev);
- pr_debug("sllin: %s() invoked\n", __FUNCTION__);
+ pr_debug("sllin: %s() invoked\n", __func__);
if (sl->tty == NULL)
return -ENODEV;
sl->rx_cnt, sl->header_received);
if (SLL_HEADER_RECEIVED) {
+ unsigned long flags;
+
lin_id = sl->rx_buff[SLLIN_BUFF_ID] & LIN_ID_MASK;
sce = &sl->linfr_cache[lin_id];
- spin_lock(&sl->lock);
+ spin_lock_irqsave(&sl->linfr_lock, flags);
/* Is the length of data set in frame cache? */
if (sce->frame_fl & LIN_LOC_SLAVE_CACHE) {
sl->rx_expect += sce->dlc;
sl->rx_expect += SLLIN_DATA_MAX + 1; /* + checksum */
sl->rx_len_unknown = true;
}
- spin_unlock(&sl->lock);
+ spin_unlock_irqrestore(&sl->linfr_lock, flags);
sl->header_received = true;
sll_send_rtr(sl);
* @sl:
* @cf: Pointer to CAN frame sent to this driver
* holding configuration information
- *
- * Called with sl->lock held.
*/
static int sllin_configure_frame_cache(struct sllin *sl, struct can_frame *cf)
{
+ unsigned long flags;
struct sllin_conf_entry *sce;
+
if (!(cf->can_id & LIN_ID_CONF))
return -1;
pr_debug("sllin: Setting frame cache with EFF CAN frame. "
"LIN ID = %d\n", cf->can_id & LIN_ID_MASK);
+ spin_lock_irqsave(&sl->linfr_lock, flags);
+
sce->dlc = cf->can_dlc;
if (sce->dlc > SLLIN_DATA_MAX)
sce->dlc = SLLIN_DATA_MAX;
sce->frame_fl = (cf->can_id & ~LIN_ID_MASK) & CAN_EFF_MASK;
memcpy(sce->data, cf->data, cf->can_dlc);
+ spin_unlock_irqrestore(&sl->linfr_lock, flags);
+
return 0;
}
unsigned csum = 0;
int i;
- if (enhanced_fl) {
+ if (enhanced_fl)
i = SLLIN_BUFF_ID;
- } else {
+ else
i = SLLIN_BUFF_DATA;
- }
for (; i < length; i++) {
csum += data[i];
int remains;
int res;
+ set_bit(SLF_TXBUFF_RQ, &sl->flags);
+ do {
+ if (unlikely(test_and_set_bit(SLF_TXBUFF_INPR, &sl->flags)))
+ return 0; /* ongoing concurrent processing */
+
+ clear_bit(SLF_TXBUFF_RQ, &sl->flags);
+ smp_mb__after_clear_bit();
+
#ifdef BREAK_BY_BAUD
- if (sl->lin_state != SLSTATE_BREAK_SENT)
- remains = sl->tx_lim - sl->tx_cnt;
- else
- remains = 1;
+ if (sl->lin_state != SLSTATE_BREAK_SENT)
+ remains = sl->tx_lim - sl->tx_cnt;
+ else
+ remains = 1;
#else
- remains = sl->tx_lim - sl->tx_cnt;
+ remains = sl->tx_lim - sl->tx_cnt;
#endif
- res = tty->ops->write(tty, sl->tx_buff + sl->tx_cnt, remains);
- if (res < 0)
- return -1;
-
- remains -= res;
- sl->tx_cnt += res;
-
- if (remains > 0) {
- set_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
res = tty->ops->write(tty, sl->tx_buff + sl->tx_cnt, remains);
- if (res < 0) {
- clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
- return -1;
- }
+ if (res < 0)
+ goto error_in_write;
remains -= res;
sl->tx_cnt += res;
- }
- pr_debug("sllin: sllin_send_tx_buff sent %d, remains %d\n",
- sl->tx_cnt, remains);
+ if (remains > 0) {
+ set_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
+ res = tty->ops->write(tty, sl->tx_buff + sl->tx_cnt, remains);
+ if (res < 0) {
+ clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
+ goto error_in_write;
+ }
+
+ remains -= res;
+ sl->tx_cnt += res;
+ }
+
+ pr_debug("sllin: sllin_send_tx_buff sent %d, remains %d\n",
+ sl->tx_cnt, remains);
+
+ clear_bit(SLF_TXBUFF_INPR, &sl->flags);
+ smp_mb__after_clear_bit();
+
+ } while (unlikely(test_bit(SLF_TXBUFF_RQ, &sl->flags)));
return 0;
+
+error_in_write:
+ clear_bit(SLF_TXBUFF_INPR, &sl->flags);
+ return -1;
+
}
#ifdef BREAK_BY_BAUD
*/
static int sllin_rx_validate(struct sllin *sl)
{
+ unsigned long flags;
int actual_id;
int ext_chcks_fl;
int lin_dlc;
unsigned char rec_chcksm = sl->rx_buff[sl->rx_cnt - 1];
- struct sllin_conf_entry *scf;
+ struct sllin_conf_entry *sce;
actual_id = sl->rx_buff[SLLIN_BUFF_ID] & LIN_ID_MASK;
- scf = &sl->linfr_cache[actual_id];
- spin_lock(&sl->lock);
- lin_dlc = scf->dlc;
- ext_chcks_fl = scf->frame_fl & LIN_CHECKSUM_EXTENDED;
- spin_unlock(&sl->lock);
+ sce = &sl->linfr_cache[actual_id];
+
+ spin_lock_irqsave(&sl->linfr_lock, flags);
+ lin_dlc = sce->dlc;
+ ext_chcks_fl = sce->frame_fl & LIN_CHECKSUM_EXTENDED;
+ spin_unlock_irqrestore(&sl->linfr_lock, flags);
if (sllin_checksum(sl->rx_buff, sl->rx_cnt - 1, ext_chcks_fl) !=
rec_chcksm) {
/* SFF RTR CAN frame -> LIN header */
if (cf->can_id & CAN_RTR_FLAG) {
- spin_lock(&sl->lock);
+ unsigned long flags;
+ struct sllin_conf_entry *sce;
+
pr_debug("sllin: %s: RTR SFF CAN frame, ID = %x\n",
- __FUNCTION__, cf->can_id & LIN_ID_MASK);
+ __func__, cf->can_id & LIN_ID_MASK);
+
+ sce = &sl->linfr_cache[cf->can_id & LIN_ID_MASK];
+ spin_lock_irqsave(&sl->linfr_lock, flags);
/* Is there Slave response in linfr_cache to be sent? */
- if ((sl->linfr_cache[cf->can_id & LIN_ID_MASK].frame_fl &
- LIN_LOC_SLAVE_CACHE)
- && (sl->linfr_cache[cf->can_id & LIN_ID_MASK].dlc > 0)) {
+ if ((sce->frame_fl & LIN_LOC_SLAVE_CACHE)
+ && (sce->dlc > 0)) {
pr_debug("sllin: Sending LIN response from linfr_cache\n");
- lin_data = sl->linfr_cache[cf->can_id & LIN_ID_MASK].data;
- lin_dlc = sl->linfr_cache[cf->can_id & LIN_ID_MASK].dlc;
+
+ lin_data = sce->data;
+ lin_dlc = sce->dlc;
if (lin_dlc > SLLIN_DATA_MAX)
lin_dlc = SLLIN_DATA_MAX;
memcpy(lin_data_buff, lin_data, lin_dlc);
lin_data = lin_data_buff;
} else {
lin_data = NULL;
- lin_dlc = sl->linfr_cache[cf->can_id & LIN_ID_MASK].dlc;
+ lin_dlc = sce->dlc;
}
- spin_unlock(&sl->lock);
+ spin_unlock_irqrestore(&sl->linfr_lock, flags);
+
} else { /* SFF NON-RTR CAN frame -> LIN header + LIN response */
pr_debug("sllin: %s: NON-RTR SFF CAN frame, ID = %x\n",
- __FUNCTION__, (int)cf->can_id & LIN_ID_MASK);
+ __func__, (int)cf->can_id & LIN_ID_MASK);
lin_data = cf->data;
lin_dlc = cf->can_dlc;
sl->magic = SLLIN_MAGIC;
sl->dev = dev;
spin_lock_init(&sl->lock);
+ spin_lock_init(&sl->linfr_lock);
sllin_devs[i] = dev;
return sl;
{
struct sllin *sl;
int err;
- pr_debug("sllin: %s() invoked\n", __FUNCTION__);
+ pr_debug("sllin: %s() invoked\n", __func__);
if (!capable(CAP_NET_ADMIN))
return -EPERM;