/** * tpm_ibmvtpm_resume - Resume from suspend * @dev: device struct * * Return value: * 0 */ static int tpm_ibmvtpm_resume(struct device *dev) { struct ibmvtpm_dev *ibmvtpm = ibmvtpm_get_data(dev); int rc = 0; do { if (rc) msleep(100); rc = plpar_hcall_norets(H_ENABLE_CRQ, ibmvtpm->vdev->unit_address); } while (rc == H_IN_PROGRESS || rc == H_BUSY || H_IS_LONG_BUSY(rc)); if (rc) { dev_err(dev, "Error enabling ibmvtpm rc=%d\n", rc); return rc; } rc = vio_enable_interrupts(ibmvtpm->vdev); if (rc) { dev_err(dev, "Error vio_enable_interrupts rc=%d\n", rc); return rc; } rc = ibmvtpm_crq_send_init(ibmvtpm); if (rc) dev_err(dev, "Error send_init rc=%d\n", rc); return rc; }
/** * ibmvscsi_task: - Process srps asynchronously * @data: ibmvscsi_host_data of host */ static void ibmvscsi_task(void *data) { struct ibmvscsi_host_data *hostdata = (struct ibmvscsi_host_data *)data; struct vio_dev *vdev = to_vio_dev(hostdata->dev); struct viosrp_crq *crq; int done = 0; while (!done) { /* Pull all the valid messages off the CRQ */ while ((crq = crq_queue_next_crq(&hostdata->queue)) != NULL) { ibmvscsi_handle_crq(crq, hostdata); crq->valid = 0x00; } vio_enable_interrupts(vdev); if ((crq = crq_queue_next_crq(&hostdata->queue)) != NULL) { vio_disable_interrupts(vdev); ibmvscsi_handle_crq(crq, hostdata); crq->valid = 0x00; } else { done = 1; } } }
/** * tpm_ibmvtpm_probe - ibm vtpm initialize entry point * @vio_dev: vio device struct * @id: vio device id struct * * Return value: * 0 - Success * Non-zero - Failure */ static int tpm_ibmvtpm_probe(struct vio_dev *vio_dev, const struct vio_device_id *id) { struct ibmvtpm_dev *ibmvtpm; struct device *dev = &vio_dev->dev; struct ibmvtpm_crq_queue *crq_q; struct tpm_chip *chip; int rc = -ENOMEM, rc1; chip = tpm_register_hardware(dev, &tpm_ibmvtpm); if (!chip) { dev_err(dev, "tpm_register_hardware failed\n"); return -ENODEV; } ibmvtpm = kzalloc(sizeof(struct ibmvtpm_dev), GFP_KERNEL); if (!ibmvtpm) { dev_err(dev, "kzalloc for ibmvtpm failed\n"); goto cleanup; } crq_q = &ibmvtpm->crq_queue; crq_q->crq_addr = (struct ibmvtpm_crq *)get_zeroed_page(GFP_KERNEL); if (!crq_q->crq_addr) { dev_err(dev, "Unable to allocate memory for crq_addr\n"); goto cleanup; } crq_q->num_entry = CRQ_RES_BUF_SIZE / sizeof(*crq_q->crq_addr); ibmvtpm->crq_dma_handle = dma_map_single(dev, crq_q->crq_addr, CRQ_RES_BUF_SIZE, DMA_BIDIRECTIONAL); if (dma_mapping_error(dev, ibmvtpm->crq_dma_handle)) { dev_err(dev, "dma mapping failed\n"); goto cleanup; } rc = plpar_hcall_norets(H_REG_CRQ, vio_dev->unit_address, ibmvtpm->crq_dma_handle, CRQ_RES_BUF_SIZE); if (rc == H_RESOURCE) rc = ibmvtpm_reset_crq(ibmvtpm); if (rc) { dev_err(dev, "Unable to register CRQ rc=%d\n", rc); goto reg_crq_cleanup; } rc = request_irq(vio_dev->irq, ibmvtpm_interrupt, 0, tpm_ibmvtpm_driver_name, ibmvtpm); if (rc) { dev_err(dev, "Error %d register irq 0x%x\n", rc, vio_dev->irq); goto init_irq_cleanup; } rc = vio_enable_interrupts(vio_dev); if (rc) { dev_err(dev, "Error %d enabling interrupts\n", rc); goto init_irq_cleanup; } init_waitqueue_head(&ibmvtpm->wq); crq_q->index = 0; ibmvtpm->dev = dev; ibmvtpm->vdev = vio_dev; chip->vendor.data = (void *)ibmvtpm; spin_lock_init(&ibmvtpm->rtce_lock); rc = ibmvtpm_crq_send_init(ibmvtpm); if (rc) goto init_irq_cleanup; rc = ibmvtpm_crq_get_version(ibmvtpm); if (rc) goto init_irq_cleanup; rc = ibmvtpm_crq_get_rtce_size(ibmvtpm); if (rc) goto init_irq_cleanup; return rc; init_irq_cleanup: do { rc1 = plpar_hcall_norets(H_FREE_CRQ, vio_dev->unit_address); } while (rc1 == H_BUSY || H_IS_LONG_BUSY(rc1)); reg_crq_cleanup: dma_unmap_single(dev, ibmvtpm->crq_dma_handle, CRQ_RES_BUF_SIZE, DMA_BIDIRECTIONAL); cleanup: if (ibmvtpm) { if (crq_q->crq_addr) free_page((unsigned long)crq_q->crq_addr); kfree(ibmvtpm); } tpm_remove_hardware(dev); return rc; }
/** * initialize_crq_queue: - Initializes and registers CRQ with hypervisor * @queue: crq_queue to initialize and register * @hostdata: ibmvscsi_host_data of host * * Allocates a page for messages, maps it for dma, and registers * the crq with the hypervisor. * Returns zero on success. */ int ibmvscsi_init_crq_queue(struct crq_queue *queue, struct ibmvscsi_host_data *hostdata, int max_requests) { int rc; int retrc; struct vio_dev *vdev = to_vio_dev(hostdata->dev); queue->msgs = (struct viosrp_crq *)get_zeroed_page(GFP_KERNEL); if (!queue->msgs) goto malloc_failed; queue->size = PAGE_SIZE / sizeof(*queue->msgs); queue->msg_token = dma_map_single(hostdata->dev, queue->msgs, queue->size * sizeof(*queue->msgs), DMA_BIDIRECTIONAL); if (dma_mapping_error(queue->msg_token)) goto map_failed; gather_partition_info(); set_adapter_info(hostdata); retrc = rc = plpar_hcall_norets(H_REG_CRQ, vdev->unit_address, queue->msg_token, PAGE_SIZE); if (rc == H_RESOURCE) /* maybe kexecing and resource is busy. try a reset */ rc = ibmvscsi_reset_crq_queue(queue, hostdata); if (rc == 2) { /* Adapter is good, but other end is not ready */ printk(KERN_WARNING "ibmvscsi: Partner adapter not ready\n"); retrc = 0; } else if (rc != 0) { printk(KERN_WARNING "ibmvscsi: Error %d opening adapter\n", rc); goto reg_crq_failed; } if (request_irq(vdev->irq, ibmvscsi_handle_event, 0, "ibmvscsi", (void *)hostdata) != 0) { printk(KERN_ERR "ibmvscsi: couldn't register irq 0x%x\n", vdev->irq); goto req_irq_failed; } rc = vio_enable_interrupts(vdev); if (rc != 0) { printk(KERN_ERR "ibmvscsi: Error %d enabling interrupts!!!\n", rc); goto req_irq_failed; } queue->cur = 0; spin_lock_init(&queue->lock); tasklet_init(&hostdata->srp_task, (void *)ibmvscsi_task, (unsigned long)hostdata); return retrc; req_irq_failed: do { rc = plpar_hcall_norets(H_FREE_CRQ, vdev->unit_address); } while ((rc == H_BUSY) || (H_IS_LONG_BUSY(rc))); reg_crq_failed: dma_unmap_single(hostdata->dev, queue->msg_token, queue->size * sizeof(*queue->msgs), DMA_BIDIRECTIONAL); map_failed: free_page((unsigned long)queue->msgs); malloc_failed: return -1; }
static int rpavscsi_init_crq_queue(struct crq_queue *queue, struct ibmvscsi_host_data *hostdata, int max_requests) { int rc; int retrc; struct vio_dev *vdev = to_vio_dev(hostdata->dev); queue->msgs = (struct viosrp_crq *)get_zeroed_page(GFP_KERNEL); if (!queue->msgs) goto malloc_failed; queue->size = PAGE_SIZE / sizeof(*queue->msgs); queue->msg_token = dma_map_single(hostdata->dev, queue->msgs, queue->size * sizeof(*queue->msgs), DMA_BIDIRECTIONAL); if (dma_mapping_error(hostdata->dev, queue->msg_token)) goto map_failed; gather_partition_info(); set_adapter_info(hostdata); retrc = rc = plpar_hcall_norets(H_REG_CRQ, vdev->unit_address, queue->msg_token, PAGE_SIZE); if (rc == H_RESOURCE) rc = rpavscsi_reset_crq_queue(queue, hostdata); if (rc == 2) { dev_warn(hostdata->dev, "Partner adapter not ready\n"); retrc = 0; } else if (rc != 0) { dev_warn(hostdata->dev, "Error %d opening adapter\n", rc); goto reg_crq_failed; } queue->cur = 0; spin_lock_init(&queue->lock); tasklet_init(&hostdata->srp_task, (void *)rpavscsi_task, (unsigned long)hostdata); if (request_irq(vdev->irq, rpavscsi_handle_event, 0, "ibmvscsi", (void *)hostdata) != 0) { dev_err(hostdata->dev, "couldn't register irq 0x%x\n", vdev->irq); goto req_irq_failed; } rc = vio_enable_interrupts(vdev); if (rc != 0) { dev_err(hostdata->dev, "Error %d enabling interrupts!!!\n", rc); goto req_irq_failed; } return retrc; req_irq_failed: tasklet_kill(&hostdata->srp_task); rc = 0; do { if (rc) msleep(100); rc = plpar_hcall_norets(H_FREE_CRQ, vdev->unit_address); } while ((rc == H_BUSY) || (H_IS_LONG_BUSY(rc))); reg_crq_failed: dma_unmap_single(hostdata->dev, queue->msg_token, queue->size * sizeof(*queue->msgs), DMA_BIDIRECTIONAL); map_failed: free_page((unsigned long)queue->msgs); malloc_failed: return -1; }