static void mhi_write_db(struct mhi_device_ctxt *mhi_dev_ctxt, void __iomem *io_addr_lower, uintptr_t chan, u64 val) { uintptr_t io_offset = chan * sizeof(u64); void __iomem *io_addr_upper = (void __iomem *)((uintptr_t)io_addr_lower + 4); mhi_reg_write(mhi_dev_ctxt, io_addr_upper, io_offset, val >> 32); mhi_reg_write(mhi_dev_ctxt, io_addr_lower, io_offset, (u32)val); }
static ssize_t bhi_write(struct file *file, const char __user *buf, size_t count, loff_t *offp) { enum MHI_STATUS ret_val = MHI_STATUS_SUCCESS; u32 pcie_word_val = 0; u32 i = 0; struct bhi_ctxt_t *bhi_ctxt = &(((struct mhi_pcie_dev_info *)file->private_data)->bhi_ctxt); struct mhi_device_ctxt *mhi_dev_ctxt = &((struct mhi_pcie_dev_info *)file->private_data)->mhi_ctxt; size_t amount_copied = 0; uintptr_t align_len = 0x1000; u32 tx_db_val = 0; if (buf == NULL || 0 == count) return -EIO; if (count > BHI_MAX_IMAGE_SIZE) return -ENOMEM; wait_event_interruptible(*mhi_dev_ctxt->mhi_ev_wq.bhi_event, mhi_dev_ctxt->mhi_state == MHI_STATE_BHI); mhi_log(MHI_MSG_INFO, "Entered. User Image size 0x%zx\n", count); bhi_ctxt->unaligned_image_loc = kmalloc(count + (align_len - 1), GFP_KERNEL); if (bhi_ctxt->unaligned_image_loc == NULL) return -ENOMEM; mhi_log(MHI_MSG_INFO, "Unaligned Img Loc: %p\n", bhi_ctxt->unaligned_image_loc); bhi_ctxt->image_loc = (void *)((uintptr_t)bhi_ctxt->unaligned_image_loc + (align_len - (((uintptr_t)bhi_ctxt->unaligned_image_loc) % align_len))); mhi_log(MHI_MSG_INFO, "Aligned Img Loc: %p\n", bhi_ctxt->image_loc); bhi_ctxt->image_size = count; if (0 != copy_from_user(bhi_ctxt->image_loc, buf, count)) { ret_val = -ENOMEM; goto bhi_copy_error; } amount_copied = count; /* Flush the writes, in anticipation for a device read */ wmb(); mhi_log(MHI_MSG_INFO, "Copied image from user at addr: %p\n", bhi_ctxt->image_loc); bhi_ctxt->phy_image_loc = dma_map_single( &mhi_dev_ctxt->dev_info->plat_dev->dev, bhi_ctxt->image_loc, bhi_ctxt->image_size, DMA_TO_DEVICE); if (dma_mapping_error(NULL, bhi_ctxt->phy_image_loc)) { ret_val = -EIO; goto bhi_copy_error; } mhi_log(MHI_MSG_INFO, "Mapped image to DMA addr 0x%lx:\n", (uintptr_t)bhi_ctxt->phy_image_loc); bhi_ctxt->image_size = count; /* Write the image size */ pcie_word_val = HIGH_WORD(bhi_ctxt->phy_image_loc); mhi_reg_write_field(mhi_dev_ctxt, bhi_ctxt->bhi_base, BHI_IMGADDR_HIGH, 0xFFFFFFFF, 0, pcie_word_val); pcie_word_val = LOW_WORD(bhi_ctxt->phy_image_loc); mhi_reg_write_field(mhi_dev_ctxt, bhi_ctxt->bhi_base, BHI_IMGADDR_LOW, 0xFFFFFFFF, 0, pcie_word_val); pcie_word_val = bhi_ctxt->image_size; mhi_reg_write_field(mhi_dev_ctxt, bhi_ctxt->bhi_base, BHI_IMGSIZE, 0xFFFFFFFF, 0, pcie_word_val); pcie_word_val = mhi_reg_read(bhi_ctxt->bhi_base, BHI_IMGTXDB); mhi_reg_write_field(mhi_dev_ctxt, bhi_ctxt->bhi_base, BHI_IMGTXDB, 0xFFFFFFFF, 0, ++pcie_word_val); mhi_reg_write(mhi_dev_ctxt, bhi_ctxt->bhi_base, BHI_INTVEC, 0); for (i = 0; i < BHI_POLL_NR_RETRIES; ++i) { tx_db_val = mhi_reg_read_field(bhi_ctxt->bhi_base, BHI_STATUS, BHI_STATUS_MASK, BHI_STATUS_SHIFT); mhi_log(MHI_MSG_CRITICAL, "BHI STATUS 0x%x\n", tx_db_val); if (BHI_STATUS_SUCCESS != tx_db_val) mhi_log(MHI_MSG_CRITICAL, "Incorrect BHI status: %d retry: %d\n", tx_db_val, i); else break; usleep_range(20000, 25000); } dma_unmap_single(&mhi_dev_ctxt->dev_info->plat_dev->dev, bhi_ctxt->phy_image_loc, bhi_ctxt->image_size, DMA_TO_DEVICE); kfree(bhi_ctxt->unaligned_image_loc); ret_val = mhi_init_state_transition(mhi_dev_ctxt, STATE_TRANSITION_RESET); if (MHI_STATUS_SUCCESS != ret_val) { mhi_log(MHI_MSG_CRITICAL, "Failed to start state change event\n"); } return amount_copied; bhi_copy_error: kfree(bhi_ctxt->unaligned_image_loc); return amount_copied; }