int cpdma_chan_start(struct cpdma_chan *chan) { struct cpdma_ctlr *ctlr = chan->ctlr; struct cpdma_desc_pool *pool = ctlr->pool; unsigned long flags; spin_lock_irqsave(&chan->lock, flags); if (chan->state != CPDMA_STATE_IDLE) { spin_unlock_irqrestore(&chan->lock, flags); return -EBUSY; } if (ctlr->state != CPDMA_STATE_ACTIVE) { spin_unlock_irqrestore(&chan->lock, flags); return -EINVAL; } dma_reg_write(ctlr, chan->int_set, chan->mask); chan->state = CPDMA_STATE_ACTIVE; if (chan->head) { chan_write(chan, hdp, desc_phys(pool, chan->head)); if (chan->rxfree) chan_write(chan, rxfree, chan->count); } spin_unlock_irqrestore(&chan->lock, flags); return 0; }
int cpdma_chan_start(struct cpdma_chan *chan) { struct cpdma_ctlr *ctlr = chan->ctlr; struct cpdma_desc_pool *pool = ctlr->pool; rtdm_lockctx_t context; rtdm_lock_get_irqsave(&chan->lock, context); if (chan->state != CPDMA_STATE_IDLE) { rtdm_lock_put_irqrestore(&chan->lock, context); return -EBUSY; } if (ctlr->state != CPDMA_STATE_ACTIVE) { rtdm_lock_put_irqrestore(&chan->lock, context); return -EINVAL; } dma_reg_write(ctlr, chan->int_set, chan->mask); chan->state = CPDMA_STATE_ACTIVE; if (chan->head) { chan_write(chan, hdp, desc_phys(pool, chan->head)); if (chan->rxfree) chan_write(chan, rxfree, chan->count); } rtdm_lock_put_irqrestore(&chan->lock, context); return 0; }
static void __cpdma_chan_submit(struct cpdma_chan *chan, struct cpdma_desc __iomem *desc) { struct cpdma_ctlr *ctlr = chan->ctlr; struct cpdma_desc __iomem *prev = chan->tail; struct cpdma_desc_pool *pool = ctlr->pool; dma_addr_t desc_dma; u32 mode; desc_dma = desc_phys(pool, desc); /* simple case - idle channel */ if (!chan->head) { chan->stats.head_enqueue++; chan->head = desc; chan->tail = desc; if (chan->state == CPDMA_STATE_ACTIVE) chan_write(chan, hdp, desc_dma); return; } /* first chain the descriptor at the tail of the list */ desc_write(prev, hw_next, desc_dma); chan->tail = desc; chan->stats.tail_enqueue++; /* next check if EOQ has been triggered already */ mode = desc_read(prev, hw_mode); if (((mode & (CPDMA_DESC_EOQ | CPDMA_DESC_OWNER)) == CPDMA_DESC_EOQ) && (chan->state == CPDMA_STATE_ACTIVE)) { desc_write(prev, hw_mode, mode & ~CPDMA_DESC_EOQ); chan_write(chan, hdp, desc_dma); chan->stats.misqueued++; } }
static int __cpdma_chan_process(struct cpdma_chan *chan) { struct cpdma_ctlr *ctlr = chan->ctlr; struct cpdma_desc __iomem *desc; int status, outlen; int cb_status = 0; struct cpdma_desc_pool *pool = ctlr->pool; dma_addr_t desc_dma; unsigned long flags; spin_lock_irqsave(&chan->lock, flags); desc = chan->head; if (!desc) { chan->stats.empty_dequeue++; status = -ENOENT; goto unlock_ret; } desc_dma = desc_phys(pool, desc); status = __raw_readl(&desc->hw_mode); outlen = status & 0x7ff; if (status & CPDMA_DESC_OWNER) { chan->stats.busy_dequeue++; status = -EBUSY; goto unlock_ret; } if (status & CPDMA_DESC_PASS_CRC) outlen -= CPDMA_DESC_CRC_LEN; status = status & (CPDMA_DESC_EOQ | CPDMA_DESC_TD_COMPLETE | CPDMA_DESC_PORT_MASK); chan->head = desc_from_phys(pool, desc_read(desc, hw_next)); chan_write(chan, cp, desc_dma); chan->count--; chan->stats.good_dequeue++; if (status & CPDMA_DESC_EOQ) { chan->stats.requeue++; chan_write(chan, hdp, desc_phys(pool, chan->head)); } spin_unlock_irqrestore(&chan->lock, flags); if (unlikely(status & CPDMA_DESC_TD_COMPLETE)) cb_status = -ENOSYS; else cb_status = status; __cpdma_chan_free(chan, desc, outlen, cb_status); return status; unlock_ret: spin_unlock_irqrestore(&chan->lock, flags); return status; }
static int test_filter(struct harness_t *harness_p) { struct chan_t chan; char buf[2]; BTASSERT(chan_init(&chan, chan_read_null, write_cb, chan_size_null) == 0); /* Write without filter function. */ buf[0] = 1; buf[1] = 2; BTASSERT(chan_write(&chan, &buf[0], 2) == 2); BTASSERT(memcmp(buffer, buf, 2) == 0); /* Filter out the message. */ BTASSERT(chan_set_write_filter_cb(&chan, write_filter) == 0); buf[0] = 1; buf[1] = 2; write_filter_return_value = 1; memset(buffer, -1, sizeof(buffer)); BTASSERT(chan_write(&chan, &buf[0], 2) == 2); buf[0] = -1; buf[1] = -1; BTASSERT(memcmp(buffer, buf, 2) == 0); BTASSERT(chan_set_write_filter_cb(&chan, NULL) == 0); /* Write isr without filter function. */ BTASSERT(chan_set_write_isr_cb(&chan, write_cb) == 0); buf[0] = 1; buf[1] = 2; BTASSERT(chan_write_isr(&chan, &buf[0], 2) == 2); BTASSERT(memcmp(buffer, buf, 2) == 0); /* Filter out the message. */ BTASSERT(chan_set_write_filter_isr_cb(&chan, write_filter) == 0); buf[0] = 1; buf[1] = 2; write_filter_return_value = 1; memset(buffer, -1, sizeof(buffer)); BTASSERT(chan_write_isr(&chan, &buf[0], 2) == 2); buf[0] = -1; buf[1] = -1; BTASSERT(memcmp(buffer, buf, 2) == 0); BTASSERT(chan_set_write_filter_isr_cb(&chan, NULL) == 0); return (0); }
static int __cpdma_chan_process(struct cpdma_chan *chan) { struct cpdma_ctlr *ctlr = chan->ctlr; struct cpdma_desc __iomem *desc; int status, outlen; struct cpdma_desc_pool *pool = ctlr->pool; dma_addr_t desc_dma; rtdm_lockctx_t context; //rtdm_printk("__cpdma_chan_process(%x)\n", chan); rtdm_lock_get_irqsave(&chan->lock, context); desc = chan->head; if (!desc) { chan->stats.empty_dequeue++; status = -ENOENT; goto unlock_ret; } desc_dma = desc_phys(pool, desc); status = __raw_readl(&desc->hw_mode); outlen = status & 0x7ff; if (status & CPDMA_DESC_OWNER) { chan->stats.busy_dequeue++; status = -EBUSY; goto unlock_ret; } status = status & (CPDMA_DESC_EOQ | CPDMA_DESC_TD_COMPLETE); chan->head = desc_from_phys(pool, desc_read(desc, hw_next)); chan_write(chan, cp, desc_dma); chan->count--; chan->stats.good_dequeue++; if (status & CPDMA_DESC_EOQ) { chan->stats.requeue++; chan_write(chan, hdp, desc_phys(pool, chan->head)); } rtdm_lock_put_irqrestore(&chan->lock, context); __cpdma_chan_free(chan, desc, outlen, status); return status; unlock_ret: rtdm_lock_put_irqrestore(&chan->lock, context); return status; }
int cpdma_chan_stop(struct cpdma_chan *chan) { struct cpdma_ctlr *ctlr = chan->ctlr; struct cpdma_desc_pool *pool = ctlr->pool; unsigned long flags; int ret; unsigned long timeout; spin_lock_irqsave(&chan->lock, flags); if (chan->state != CPDMA_STATE_ACTIVE) { spin_unlock_irqrestore(&chan->lock, flags); return -EINVAL; } chan->state = CPDMA_STATE_TEARDOWN; dma_reg_write(ctlr, chan->int_clear, chan->mask); /* trigger teardown */ dma_reg_write(ctlr, chan->td, chan_linear(chan)); /* wait for teardown complete */ timeout = jiffies + HZ/10; /* 100 msec */ while (time_before(jiffies, timeout)) { u32 cp = chan_read(chan, cp); if ((cp & CPDMA_TEARDOWN_VALUE) == CPDMA_TEARDOWN_VALUE) break; cpu_relax(); } WARN_ON(!time_before(jiffies, timeout)); chan_write(chan, cp, CPDMA_TEARDOWN_VALUE); /* handle completed packets */ spin_unlock_irqrestore(&chan->lock, flags); do { ret = __cpdma_chan_process(chan); if (ret < 0) break; } while ((ret & CPDMA_DESC_TD_COMPLETE) == 0); spin_lock_irqsave(&chan->lock, flags); /* remaining packets haven't been tx/rx'ed, clean them up */ while (chan->head) { struct cpdma_desc __iomem *desc = chan->head; dma_addr_t next_dma; next_dma = desc_read(desc, hw_next); chan->head = desc_from_phys(pool, next_dma); chan->count--; chan->stats.teardown_dequeue++; /* issue callback without locks held */ spin_unlock_irqrestore(&chan->lock, flags); __cpdma_chan_free(chan, desc, 0, -ENOSYS); spin_lock_irqsave(&chan->lock, flags); } chan->state = CPDMA_STATE_IDLE; spin_unlock_irqrestore(&chan->lock, flags); return 0; }
static int __cpdma_chan_process(struct cpdma_chan *chan) { struct cpdma_ctlr *ctlr = chan->ctlr; struct cpdma_desc __iomem *desc; u32 status, outlen; struct cpdma_desc_pool *pool = ctlr->pool; dma_addr_t desc_dma; unsigned long flags; spin_lock_irqsave(&chan->lock, flags); desc = chan->head; if (!desc) { chan->stats.empty_dequeue++; status = -ENOENT; goto unlock_ret; } desc_dma = desc_phys(pool, desc); status = __raw_readl(&desc->hw_mode); outlen = status & 0x7ff; if (status & CPDMA_DESC_OWNER) { chan->stats.busy_dequeue++; status = -EBUSY; goto unlock_ret; } status = status & (CPDMA_DESC_EOQ | CPDMA_DESC_TD_COMPLETE); chan->head = desc_from_phys(pool, desc_read(desc, sw_next)); chan_write(chan, cp, desc_dma); chan->count--; chan->stats.good_dequeue++; if ((status & CPDMA_DESC_EOQ) && (chan->head) && (!(status & CPDMA_DESC_TD_COMPLETE))) { chan->stats.requeue++; chan_write(chan, hdp, desc_phys(pool, chan->head)); } spin_unlock_irqrestore(&chan->lock, flags); __cpdma_chan_free(chan, desc, outlen, (int)status); return status; unlock_ret: spin_unlock_irqrestore(&chan->lock, flags); return status; }
int cpdma_chan_submit(struct cpdma_chan *chan, void *token, void *data, int len, int directed) { struct cpdma_ctlr *ctlr = chan->ctlr; struct cpdma_desc __iomem *desc; dma_addr_t buffer; unsigned long flags; u32 mode; int ret = 0; spin_lock_irqsave(&chan->lock, flags); if (chan->state == CPDMA_STATE_TEARDOWN) { ret = -EINVAL; goto unlock_ret; } desc = cpdma_desc_alloc(ctlr->pool, 1, is_rx_chan(chan)); if (!desc) { chan->stats.desc_alloc_fail++; ret = -ENOMEM; goto unlock_ret; } if (len < ctlr->params.min_packet_size) { len = ctlr->params.min_packet_size; chan->stats.runt_transmit_buff++; } buffer = dma_map_single(ctlr->dev, data, len, chan->dir); ret = dma_mapping_error(ctlr->dev, buffer); if (ret) { cpdma_desc_free(ctlr->pool, desc, 1); ret = -EINVAL; goto unlock_ret; } mode = CPDMA_DESC_OWNER | CPDMA_DESC_SOP | CPDMA_DESC_EOP; cpdma_desc_to_port(chan, mode, directed); desc_write(desc, hw_next, 0); desc_write(desc, hw_buffer, buffer); desc_write(desc, hw_len, len); desc_write(desc, hw_mode, mode | len); desc_write(desc, sw_token, token); desc_write(desc, sw_buffer, buffer); desc_write(desc, sw_len, len); __cpdma_chan_submit(chan, desc); if (chan->state == CPDMA_STATE_ACTIVE && chan->rxfree) chan_write(chan, rxfree, 1); chan->count++; unlock_ret: spin_unlock_irqrestore(&chan->lock, flags); return ret; }
static int cmd_at_cb(int argc, const char *argv[], void *out_p, void *in_p, void *arg_p, void *call_arg_p) { struct chan_list_t list; void *chan_p; char c; char buf[32]; std_fprintf(out_p, OSTR("type ctrl-d to exit\r\n")); /* Wait for data from PC and HC-0X. */ chan_list_init(&list, buf, sizeof(buf)); chan_list_add(&list, &uart.chin); chan_list_add(&list, in_p); /* Pass data between PC and bluetooth device. */ while (1) { chan_p = chan_list_poll(&list, NULL); if (chan_p == in_p) { chan_read(chan_p, &c, sizeof(c)); /* break if EOT is found, otherwise write to HC-0X. */ if (c == EOT) { break; } chan_write(&uart.chout, &c, sizeof(c)); } else if (chan_p == &uart.chin) { /* Write all output from HC-0X to the PC. */ chan_read(chan_p, &c, sizeof(c)); chan_write(out_p, &c, sizeof(c)); } else { std_printf(OSTR("bad input channel 0x%02x\r\n"), (int)chan_p); } } chan_list_destroy(&list); return (0); }
ssize_t can_write(struct can_driver_t *self_p, const struct can_frame_t *frame_p, size_t size) { ASSERTN(self_p != NULL, EINVAL); ASSERTN(frame_p != NULL, EINVAL); ASSERTN(size > 0, EINVAL); return (chan_write(&self_p->base, frame_p, size)); }
int cpdma_chan_submit(struct cpdma_chan *chan, void *token, void *data, int len, gfp_t gfp_mask) { struct cpdma_ctlr *ctlr = chan->ctlr; struct cpdma_desc __iomem *desc; dma_addr_t buffer; rtdm_lockctx_t context; u32 mode; int ret = 0; rtdm_lock_get_irqsave(&chan->lock, context); if (chan->state == CPDMA_STATE_TEARDOWN) { ret = -EINVAL; goto unlock_ret; } desc = cpdma_desc_alloc(ctlr->pool, 1); if (!desc) { chan->stats.desc_alloc_fail++; ret = -ENOMEM; goto unlock_ret; } if (len < ctlr->params.min_packet_size) { len = ctlr->params.min_packet_size; chan->stats.runt_transmit_buff++; } buffer = dma_map_single(ctlr->dev, data, len, chan->dir); mode = CPDMA_DESC_OWNER | CPDMA_DESC_SOP | CPDMA_DESC_EOP; desc_write(desc, hw_next, 0); desc_write(desc, hw_buffer, buffer); desc_write(desc, hw_len, len); desc_write(desc, hw_mode, mode | len); desc_write(desc, sw_token, token); desc_write(desc, sw_buffer, buffer); desc_write(desc, sw_len, len); __cpdma_chan_submit(chan, desc); if (chan->state == CPDMA_STATE_ACTIVE && chan->rxfree) chan_write(chan, rxfree, 1); chan->count++; unlock_ret: rtdm_lock_put_irqrestore(&chan->lock, context); return ret; }
static int test_null_channels(struct harness_t *harness_p) { struct chan_t chan; char value; BTASSERT(chan_init(&chan, chan_read_null, chan_write_null, chan_size_null) == 0); BTASSERT(chan_read(&chan, &value, 1) == -1); BTASSERT(chan_write(&chan, &value, 1) == 1); BTASSERT(chan_size(&chan) == 1); return (0); }
static ssize_t write(void *self_p, const void *buf_p, size_t size) { return (chan_write(&qoutput, buf_p, size)); }