static int ilo_pkt_dequeue(struct ilo_hwinfo *hw, struct ccb *ccb, int dir, int *id, int *len, void **pkt) { char *fifobar, *desc; int entry = 0, pkt_id = 0; int ret; if (dir == SENDQ) { fifobar = ccb->ccb_u1.send_fifobar; desc = ccb->ccb_u2.send_desc; } else { fifobar = ccb->ccb_u3.recv_fifobar; desc = ccb->ccb_u4.recv_desc; } ret = fifo_dequeue(hw, fifobar, &entry); if (ret) { pkt_id = get_entry_id(entry); if (id) *id = pkt_id; if (len) *len = get_entry_len(entry); if (pkt) *pkt = (void *)(desc + desc_mem_sz(pkt_id)); } return ret; }
static ssize_t ilo_read(struct file *fp, char __user *buf, size_t len, loff_t *off) { int err, found, cnt, pkt_id, pkt_len; struct ccb_data *data = fp->private_data; struct ccb *driver_ccb = &data->driver_ccb; struct ilo_hwinfo *hw = data->ilo_hw; void *pkt; if (is_channel_reset(driver_ccb)) { /* * If the device has been reset, applications * need to close and reopen all ccbs. */ return -ENODEV; } /* * This function is to be called when data is expected * in the channel, and will return an error if no packet is found * during the loop below. The sleep/retry logic is to allow * applications to call read() immediately post write(), * and give iLO some time to process the sent packet. */ cnt = 20; do { /* look for a received packet */ found = ilo_pkt_dequeue(hw, driver_ccb, RECVQ, &pkt_id, &pkt_len, &pkt); if (found) break; cnt--; msleep(100); } while (!found && cnt); if (!found) return -EAGAIN; /* only copy the length of the received packet */ if (pkt_len < len) len = pkt_len; err = copy_to_user(buf, pkt, len); /* return the received packet to the queue */ ilo_pkt_enqueue(hw, driver_ccb, RECVQ, pkt_id, desc_mem_sz(1)); return err ? -EFAULT : len; }
static ssize_t ilo_read(struct file *fp, char __user *buf, size_t len, loff_t *off) { int err, found, cnt, pkt_id, pkt_len; struct ccb_data *data = fp->private_data; struct ccb *driver_ccb = &data->driver_ccb; struct ilo_hwinfo *hw = data->ilo_hw; void *pkt; if (is_channel_reset(driver_ccb)) { /* */ return -ENODEV; } /* */ cnt = 20; do { /* */ found = ilo_pkt_dequeue(hw, driver_ccb, RECVQ, &pkt_id, &pkt_len, &pkt); if (found) break; cnt--; msleep(100); } while (!found && cnt); if (!found) return -EAGAIN; /* */ if (pkt_len < len) len = pkt_len; err = copy_to_user(buf, pkt, len); /* */ ilo_pkt_enqueue(hw, driver_ccb, RECVQ, pkt_id, desc_mem_sz(1)); return err ? -EFAULT : len; }
static void ilo_ccb_open(struct ilo_hwinfo *hw, struct ccb_data *data, int slot) { int pkt_id, pkt_sz; struct ccb *driver_ccb = &data->driver_ccb; /* copy the ccb with physical addrs to device memory */ data->mapped_ccb = (struct ccb __iomem *) (hw->ram_vaddr + (slot * ILOHW_CCB_SZ)); memcpy_toio(data->mapped_ccb, &data->ilo_ccb, sizeof(struct ccb)); /* put packets on the send and receive queues */ pkt_sz = 0; for (pkt_id = 0; pkt_id < NR_QENTRY; pkt_id++) { ilo_pkt_enqueue(hw, driver_ccb, SENDQ, pkt_id, pkt_sz); doorbell_set(driver_ccb); } pkt_sz = desc_mem_sz(1); for (pkt_id = 0; pkt_id < NR_QENTRY; pkt_id++) ilo_pkt_enqueue(hw, driver_ccb, RECVQ, pkt_id, pkt_sz); /* the ccb is ready to use */ doorbell_clr(driver_ccb); }
static void ilo_ccb_open(struct ilo_hwinfo *hw, struct ccb_data *data, int slot) { int pkt_id, pkt_sz; struct ccb *driver_ccb = &data->driver_ccb; /* */ data->mapped_ccb = (struct ccb __iomem *) (hw->ram_vaddr + (slot * ILOHW_CCB_SZ)); memcpy_toio(data->mapped_ccb, &data->ilo_ccb, sizeof(struct ccb)); /* */ pkt_sz = 0; for (pkt_id = 0; pkt_id < NR_QENTRY; pkt_id++) { ilo_pkt_enqueue(hw, driver_ccb, SENDQ, pkt_id, pkt_sz); doorbell_set(driver_ccb); } pkt_sz = desc_mem_sz(1); for (pkt_id = 0; pkt_id < NR_QENTRY; pkt_id++) ilo_pkt_enqueue(hw, driver_ccb, RECVQ, pkt_id, pkt_sz); /* */ doorbell_clr(driver_ccb); }
static int ilo_ccb_setup(struct ilo_hwinfo *hw, struct ccb_data *data, int slot) { char *dma_va; dma_addr_t dma_pa; struct ccb *driver_ccb, *ilo_ccb; driver_ccb = &data->driver_ccb; ilo_ccb = &data->ilo_ccb; data->dma_size = 2 * fifo_sz(NR_QENTRY) + 2 * desc_mem_sz(NR_QENTRY) + ILO_START_ALIGN + ILO_CACHE_SZ; data->dma_va = pci_alloc_consistent(hw->ilo_dev, data->dma_size, &data->dma_pa); if (!data->dma_va) return -ENOMEM; dma_va = (char *)data->dma_va; dma_pa = data->dma_pa; memset(dma_va, 0, data->dma_size); dma_va = (char *)roundup((unsigned long)dma_va, ILO_START_ALIGN); dma_pa = roundup(dma_pa, ILO_START_ALIGN); /* * Create two ccb's, one with virt addrs, one with phys addrs. * Copy the phys addr ccb to device shared mem. */ ctrl_setup(driver_ccb, NR_QENTRY, L2_QENTRY_SZ); ctrl_setup(ilo_ccb, NR_QENTRY, L2_QENTRY_SZ); fifo_setup(dma_va, NR_QENTRY); driver_ccb->ccb_u1.send_fifobar = dma_va + FIFOHANDLESIZE; ilo_ccb->ccb_u1.send_fifobar_pa = dma_pa + FIFOHANDLESIZE; dma_va += fifo_sz(NR_QENTRY); dma_pa += fifo_sz(NR_QENTRY); dma_va = (char *)roundup((unsigned long)dma_va, ILO_CACHE_SZ); dma_pa = roundup(dma_pa, ILO_CACHE_SZ); fifo_setup(dma_va, NR_QENTRY); driver_ccb->ccb_u3.recv_fifobar = dma_va + FIFOHANDLESIZE; ilo_ccb->ccb_u3.recv_fifobar_pa = dma_pa + FIFOHANDLESIZE; dma_va += fifo_sz(NR_QENTRY); dma_pa += fifo_sz(NR_QENTRY); driver_ccb->ccb_u2.send_desc = dma_va; ilo_ccb->ccb_u2.send_desc_pa = dma_pa; dma_pa += desc_mem_sz(NR_QENTRY); dma_va += desc_mem_sz(NR_QENTRY); driver_ccb->ccb_u4.recv_desc = dma_va; ilo_ccb->ccb_u4.recv_desc_pa = dma_pa; driver_ccb->channel = slot; ilo_ccb->channel = slot; driver_ccb->ccb_u5.db_base = hw->db_vaddr + (slot << L2_DB_SIZE); ilo_ccb->ccb_u5.db_base = NULL; /* hw ccb's doorbell is not used */ return 0; }