if (!bcm_vk_drv_access_ok(vk)) {
dev_err(&vk->pdev->dev, "Interrupt %d received when msgq not inited\n", irq); goto skip_schedule_work;
}
/* if notification is not pending, set bit and schedule work */ if (test_and_set_bit(BCM_VK_WQ_NOTF_PEND, vk->wq_offload) == 0)
queue_work(vk->wq_thread, &vk->wq_work);
skip_schedule_work: return IRQ_HANDLED;
}
staticint bcm_vk_intf_ver_chk(struct bcm_vk *vk)
{ struct device *dev = &vk->pdev->dev;
u32 reg;
u16 major, minor; int ret = 0;
/* check and make copy of alert with lock and then free lock */
spin_lock_irqsave(&vk->host_alert_lock, flags); if (intf_down)
vk->host_alert.notfs |= ERR_LOG_HOST_PCIE_DWN;
/* first read the offset from spare register */
offset = vkread32(vk, BAR_0, BAR_CARD_STATIC_INFO);
offset &= (pci_resource_len(vk->pdev, BAR_2 * 2) - 1);
/* based on the offset, read info to internal card info structure */
dst = (u8 *)info; for (i = 0; i < sizeof(*info); i++)
*dst++ = vkread8(vk, BAR_2, offset++);
/* calculate offset which is based on peerlog offset */
buf_size = vkread32(vk, BAR_2,
vk->peerlog_off
+ offsetof(struct bcm_vk_peer_log, buf_size));
offset = vk->peerlog_off + sizeof(struct bcm_vk_peer_log)
+ buf_size;
/* first read the num and entry size */
num = vkread32(vk, BAR_2, offset);
entry_size = vkread32(vk, BAR_2, offset + sizeof(num));
/* check for max allowed */ if (num > BCM_VK_PROC_MON_MAX) {
dev_err(dev, "Processing monitoring entry %d exceeds max %d\n",
num, BCM_VK_PROC_MON_MAX); return;
}
mon->num = num;
mon->entry_size = entry_size;
vk->proc_mon_off = offset;
/* read it once that will capture those static info */
dst = (u8 *)&mon->entries[0];
offset += sizeof(num) + sizeof(entry_size);
memcpy_fromio(dst, vk->bar[BAR_2] + offset, num * entry_size);
}
/* To send more data to VK than max_buf allowed at a time */ do { /* *Checkforackfromcard.whenAckisreceived, *itmeansallthedataisreceivedbycard. *Exittheloopafterackisreceived.
*/
ret = bcm_vk_wait(vk, BAR_0, BAR_BOOT_STATUS,
FW_LOADER_ACK_RCVD_ALL_DATA,
FW_LOADER_ACK_RCVD_ALL_DATA,
TXFR_COMPLETE_TIMEOUT_MS); if (ret == 0) {
dev_dbg(dev, "Exit boot2 download\n"); break;
} elseif (ret == -EFAULT) {
dev_err(dev, "Error detected during ACK waiting"); goto err_firmware_out;
}
/* exit the loop, if there is no response from card */ if (time_after(jiffies, timeout)) {
dev_err(dev, "Error. No reply from card\n");
ret = -ETIMEDOUT; goto err_firmware_out;
}
/* Wait for VK to open BAR space to copy new data */
ret = bcm_vk_wait(vk, BAR_0, offset_codepush,
codepush, 0,
TXFR_COMPLETE_TIMEOUT_MS); if (ret == 0) {
offset += max_buf;
ret = request_partial_firmware_into_buf
(&fw,
filename,
dev, bufp,
max_buf,
offset); if (ret) {
dev_err(dev, "Error %d requesting firmware file: %s offset: 0x%zx\n",
ret, filename, offset); goto err_firmware_out;
}
dev_dbg(dev, "size=0x%zx\n", fw->size);
dev_dbg(dev, "Signaling 0x%x to 0x%llx\n",
codepush, offset_codepush);
vkwrite32(vk, codepush, BAR_0, offset_codepush); /* reload timeout after every codepush */
timeout = jiffies +
msecs_to_jiffies(LOAD_IMAGE_TIMEOUT_MS);
} elseif (ret == -EFAULT) {
dev_err(dev, "Error detected waiting for transfer\n"); goto err_firmware_out;
}
} while (1);
/* wait for fw status bits to indicate app ready */
ret = bcm_vk_wait(vk, BAR_0, VK_BAR_FWSTS,
VK_FWSTS_READY,
VK_FWSTS_READY,
BOOT2_STARTUP_TIMEOUT_MS); if (ret < 0) {
dev_err(dev, "Boot2 not ready - ret(%d)\n", ret); goto err_firmware_out;
}
is_stdalone = vkread32(vk, BAR_0, BAR_BOOT_STATUS) &
BOOT_STDALONE_RUNNING; if (!is_stdalone) {
ret = bcm_vk_intf_ver_chk(vk); if (ret) {
dev_err(dev, "failure in intf version check\n"); goto err_firmware_out;
}
/* *Next,initializeMessageQifweareloadingboot2. *Doaforcesync
*/
ret = bcm_vk_sync_msgq(vk, true); if (ret) {
dev_err(dev, "Boot2 Error reading comm msg Q info\n");
ret = -EIO; goto err_firmware_out;
}
/* sync & channel other info */
ret = bcm_vk_sync_card_info(vk); if (ret) {
dev_err(dev, "Syncing Card Info failure\n"); goto err_firmware_out;
}
}
}
err_firmware_out:
release_firmware(fw);
err_buf_out: if (bufp)
dma_free_coherent(dev, max_buf, bufp, boot_dma_addr);
/* Log status so that we know different stages */
dev_info(&vk->pdev->dev, "boot-status value for next image: 0x%x : fw-status 0x%x\n",
boot_status, fw_status);
switch (pdev->device) { case PCI_DEVICE_ID_VALKYRIE: /* get the chip id to decide sub-class */
rev = MAJOR_SOC_REV(vkread32(vk, BAR_0, BAR_CHIP_ID)); if (rev < ARRAY_SIZE(vk_soc_tab)) {
idx = vk_soc_tab[rev];
} else { /* Default to A0 firmware for all other chip revs */
idx = VALKYRIE_A0;
dev_warn(&pdev->dev, "Rev %d not in image lookup table, default to idx=%d\n",
rev, idx);
} break;
case PCI_DEVICE_ID_VIPER:
idx = VIPER; break;
default:
dev_err(&pdev->dev, "no images for 0x%x\n", pdev->device);
} return idx;
}
for (i = 0; i < IMG_PER_TYPE_MAX; i++) {
fw = NULL;
ret = request_partial_firmware_into_buf(&fw,
entry->image_name[i],
dev, &dummy, sizeof(dummy), 0);
release_firmware(fw); if (!ret) return entry->image_name[i];
} return NULL;
}
int bcm_vk_auto_load_all_images(struct bcm_vk *vk)
{ int i, ret = -1; enum soc_idx idx; struct device *dev = &vk->pdev->dev;
u32 curr_type; constchar *curr_name;
idx = get_soc_idx(vk); if (idx == VK_IDX_INVALID) goto auto_load_all_exit;
/* log a message to know the relative loading order */
dev_dbg(dev, "Load All for device %d\n", vk->devid);
for (i = 0; i < NUM_BOOT_STAGES; i++) {
curr_type = image_tab[idx][i].image_type; if (bcm_vk_next_boot_image(vk) == curr_type) {
curr_name = get_load_fw_name(vk, &image_tab[idx][i]); if (!curr_name) {
dev_err(dev, "No suitable firmware exists for type %d",
curr_type);
ret = -ENOENT; goto auto_load_all_exit;
}
ret = bcm_vk_load_image_by_type(vk, curr_type,
curr_name);
dev_info(dev, "Auto load %s, ret %d\n",
curr_name, ret);
/* check wq offload bit map to perform various operations */ if (test_bit(BCM_VK_WQ_NOTF_PEND, vk->wq_offload)) { /* clear bit right the way for notification */
clear_bit(BCM_VK_WQ_NOTF_PEND, vk->wq_offload);
bcm_vk_handle_notf(vk);
} if (test_bit(BCM_VK_WQ_DWNLD_AUTO, vk->wq_offload)) {
bcm_vk_auto_load_all_images(vk);
image_name = image.filename; if (image_name[0] == '\0') { /* Use default image name if NULL */
idx = get_soc_idx(vk); if (idx == VK_IDX_INVALID) goto err_idx;
/* Image idx starts with boot1 */
image_idx = image.type - VK_IMAGE_TYPE_BOOT1;
image_name = get_load_fw_name(vk, &image_tab[idx][image_idx]); if (!image_name) {
dev_err(dev, "No suitable image found for type %d",
image.type);
ret = -ENOENT; goto err_idx;
}
} else { /* Ensure filename is NULL terminated */
image.filename[sizeof(image.filename) - 1] = '\0';
}
ret = bcm_vk_load_image_by_type(vk, image.type, image_name);
dev_info(dev, "Load %s, ret %d\n", image_name, ret);
err_idx:
clear_bit(BCM_VK_WQ_DWNLD_PEND, vk->wq_offload);
return ret;
}
staticint bcm_vk_reset_successful(struct bcm_vk *vk)
{ struct device *dev = &vk->pdev->dev;
u32 fw_status, reset_reason; int ret = -EAGAIN;
/* clean up before pressing the door bell */
bcm_vk_drain_msg_on_reset(vk);
vkwrite32(vk, 0, BAR_1, VK_BAR1_MSGQ_DEF_RDY); /* make tag '\0' terminated */
vkwrite32(vk, 0, BAR_1, VK_BAR1_BOOT1_VER_TAG);
for (i = 0; i < VK_BAR1_DAUTH_MAX; i++) {
vkwrite32(vk, 0, BAR_1, VK_BAR1_DAUTH_STORE_ADDR(i));
vkwrite32(vk, 0, BAR_1, VK_BAR1_DAUTH_VALID_ADDR(i));
} for (i = 0; i < VK_BAR1_SOTP_REVID_MAX; i++)
vkwrite32(vk, 0, BAR_1, VK_BAR1_SOTP_REVID_ADDR(i));
/* reset fw_status with proper reason, and press db */
vkwrite32(vk, VK_FWSTS_RESET_MBOX_DB, BAR_0, VK_BAR_FWSTS);
bcm_to_v_reset_doorbell(vk, VK_BAR0_RESET_DB_SOFT);
/* clear other necessary registers and alert records */ for (i = 0; i < ARRAY_SIZE(bar0_reg_clr_list); i++)
vkwrite32(vk, 0, BAR_0, bar0_reg_clr_list[i]);
memset(&vk->host_alert, 0, sizeof(vk->host_alert));
memset(&vk->peer_alert, 0, sizeof(vk->peer_alert)); /* clear 4096 bits of bitmap */
bitmap_clear(vk->bmap, 0, VK_MSG_ID_BITMAP_SIZE);
return0;
}
staticlong bcm_vk_reset(struct bcm_vk *vk, struct vk_reset __user *arg)
{ struct device *dev = &vk->pdev->dev; struct vk_reset reset; int ret = 0;
u32 ramdump_reset; int special_reset;
if (copy_from_user(&reset, arg, sizeof(struct vk_reset))) return -EFAULT;
/* check if any download is in-progress, if so return error */ if (test_and_set_bit(BCM_VK_WQ_DWNLD_PEND, vk->wq_offload) != 0) {
dev_err(dev, "Download operation pending - skip reset.\n"); return -EPERM;
}
if (special_reset) { /* if it is special ramdump reset, return the type to user */
reset.arg2 = special_reset; if (copy_to_user(arg, &reset, sizeof(reset)))
ret = -EFAULT;
} else {
ret = bcm_vk_reset_successful(vk);
}
/* make sure DMA is good */
err = dma_set_mask_and_coherent(&pdev->dev,
DMA_BIT_MASK(BCM_VK_DMA_BITS)); if (err) {
dev_err(dev, "failed to set DMA mask\n"); goto err_disable_pdev;
}
/* The tdma is a scratch area for some DMA testings. */ if (nr_scratch_pages) {
vk->tdma_vaddr = dma_alloc_coherent
(dev,
nr_scratch_pages * PAGE_SIZE,
&vk->tdma_addr, GFP_KERNEL); if (!vk->tdma_vaddr) {
err = -ENOMEM; goto err_disable_pdev;
}
}
if (irq < VK_MSIX_IRQ_MIN_REQ) {
dev_err(dev, "failed to get min %d MSIX interrupts, irq(%d)\n",
VK_MSIX_IRQ_MIN_REQ, irq);
err = (irq >= 0) ? -EINVAL : irq; goto err_disable_pdev;
}
if (irq != VK_MSIX_IRQ_MAX)
dev_warn(dev, "Number of IRQs %d allocated - requested(%d).\n",
irq, VK_MSIX_IRQ_MAX);
for (i = 0; i < MAX_BAR; i++) { /* multiple by 2 for 64 bit BAR mapping */
vk->bar[i] = pci_ioremap_bar(pdev, i * 2); if (!vk->bar[i]) {
dev_err(dev, "failed to remap BAR%d\n", i);
err = -ENOMEM; goto err_iounmap;
}
}
for (vk->num_irqs = 0;
vk->num_irqs < VK_MSIX_MSGQ_MAX;
vk->num_irqs++) {
err = devm_request_irq(dev, pci_irq_vector(pdev, vk->num_irqs),
bcm_vk_msgq_irqhandler,
IRQF_SHARED, DRV_MODULE_NAME, vk); if (err) {
dev_err(dev, "failed to request msgq IRQ %d for MSIX %d\n",
pdev->irq + vk->num_irqs, vk->num_irqs + 1); goto err_irq;
}
} /* one irq for notification from VK */
err = devm_request_irq(dev, pci_irq_vector(pdev, vk->num_irqs),
bcm_vk_notf_irqhandler,
IRQF_SHARED, DRV_MODULE_NAME, vk); if (err) {
dev_err(dev, "failed to request notf IRQ %d for MSIX %d\n",
pdev->irq + vk->num_irqs, vk->num_irqs + 1); goto err_irq;
}
vk->num_irqs++;
for (i = 0;
(i < VK_MSIX_TTY_MAX) && (vk->num_irqs < irq);
i++, vk->num_irqs++) {
err = devm_request_irq(dev, pci_irq_vector(pdev, vk->num_irqs),
bcm_vk_tty_irqhandler,
IRQF_SHARED, DRV_MODULE_NAME, vk); if (err) {
dev_err(dev, "failed request tty IRQ %d for MSIX %d\n",
pdev->irq + vk->num_irqs, vk->num_irqs + 1); goto err_irq;
}
bcm_vk_tty_set_irq_enabled(vk, i);
}
id = ida_alloc(&bcm_vk_ida, GFP_KERNEL); if (id < 0) {
err = id;
dev_err(dev, "unable to get id\n"); goto err_irq;
}
if (vk->tdma_vaddr)
dma_free_coherent(&pdev->dev, nr_scratch_pages * PAGE_SIZE,
vk->tdma_vaddr, vk->tdma_addr);
/* remove if name is set which means misc dev registered */ if (misc_device->name) {
misc_deregister(misc_device);
kfree(misc_device->name);
ida_free(&bcm_vk_ida, vk->devid);
} for (i = 0; i < vk->num_irqs; i++)
devm_free_irq(&pdev->dev, pci_irq_vector(pdev, i), vk);
if (boot_stat == BOOT1_RUNNING) { /* simply trigger a reset interrupt to park it */
bcm_vk_trigger_reset(vk);
} elseif (boot_stat == BROM_NOT_RUN) { int err;
u16 lnksta;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.