/** * heci_start - initializes host and fw to start work. * * @dev: the device structure * * returns 0 on success, <0 on failure. */ int heci_start(struct heci_device *dev) { heci_hw_config(dev); #ifdef FORCE_FW_INIT_RESET /* wait for FW-initiated reset flow, indefinitely */ heci_hw_start(dev); heci_enable_interrupts(dev); timed_wait_for_timeout(WAIT_FOR_CONNECT_SLICE, dev->recvd_hw_ready, (2*HZ)); /* Lock only after FW-reset flow worked or failed. * Otherwise interrupts BH will be locked */ mutex_lock(&dev->device_lock); if (dev->recvd_hw_ready) goto reset_done; #else mutex_lock(&dev->device_lock); #endif /* acknowledge interrupt and stop interupts */ heci_clear_interrupts(dev); dev_dbg(&dev->pdev->dev, "reset in start the heci device.\n"); heci_reset(dev, 1); reset_done: if (heci_hbm_start_wait(dev)) { dev_err(&dev->pdev->dev, "HBM haven't started"); goto err; } if (!heci_host_is_ready(dev)) { dev_err(&dev->pdev->dev, "host is not ready.\n"); goto err; } if (!heci_hw_is_ready(dev)) { dev_err(&dev->pdev->dev, "ME is not ready.\n"); goto err; } /*if (dev->version.major_version != HBM_MAJOR_VERSION || dev->version.minor_version != HBM_MINOR_VERSION) { dev_dbg(&dev->pdev->dev, "HECI start failed.\n"); goto err; }*/ dev_dbg(&dev->pdev->dev, "link layer has been established.\n"); mutex_unlock(&dev->device_lock); return 0; err: dev_err(&dev->pdev->dev, "link layer initialization failed.\n"); dev->dev_state = HECI_DEV_DISABLED; mutex_unlock(&dev->device_lock); return -ENODEV; }
void heci_stop(struct heci_device *dev) { dev_dbg(&dev->pdev->dev, "stopping the device.\n"); mutex_lock(&dev->device_lock); cancel_delayed_work(&dev->timer_work); dev->dev_state = HECI_DEV_POWER_DOWN; heci_reset(dev, 0); mutex_unlock(&dev->device_lock); flush_scheduled_work(); }
/* * heci_hw_init - init host and fw to start work. * * @dev: Device object for our driver * * @return 0 on success, <0 on failure. */ int heci_hw_init(struct iamt_heci_device *dev) { int err = 0; mutex_enter(&dev->device_lock); dev->host_hw_state = read_heci_register(dev, H_CSR); dev->me_hw_state = read_heci_register(dev, ME_CSR_HA); DBG("host_hw_state = 0x%08x, mestate = 0x%08x.\n", dev->host_hw_state, dev->me_hw_state); if ((dev->host_hw_state & H_IS) == H_IS) { /* acknowledge interrupt and stop interupts */ heci_set_csr_register(dev); } dev->recvd_msg = 0; DBG("reset in start the heci device.\n"); heci_reset(dev, 1); DBG("host_hw_state = 0x%08x, me_hw_state = 0x%08x.\n", dev->host_hw_state, dev->me_hw_state); /* wait for ME to turn on ME_RDY */ err = 0; while (!dev->recvd_msg && err != -1) { err = cv_reltimedwait(&dev->wait_recvd_msg, &dev->device_lock, HECI_INTEROP_TIMEOUT, TR_CLOCK_TICK); } if (err == -1 && !dev->recvd_msg) { dev->heci_state = HECI_DISABLED; DBG("wait_event_interruptible_timeout failed" "on wait for ME to turn on ME_RDY.\n"); mutex_exit(&dev->device_lock); return (-ENODEV); } else { if (!(((dev->host_hw_state & H_RDY) == H_RDY) && ((dev->me_hw_state & ME_RDY_HRA) == ME_RDY_HRA))) { dev->heci_state = HECI_DISABLED; DBG("host_hw_state = 0x%08x, me_hw_state = 0x%08x.\n", dev->host_hw_state, dev->me_hw_state); if (!(dev->host_hw_state & H_RDY) != H_RDY) DBG("host turn off H_RDY.\n"); if (!(dev->me_hw_state & ME_RDY_HRA) != ME_RDY_HRA) DBG("ME turn off ME_RDY.\n"); cmn_err(CE_WARN, "heci: link layer initialization failed.\n"); mutex_exit(&dev->device_lock); return (-ENODEV); } } dev->recvd_msg = 0; DBG("host_hw_state = 0x%08x, me_hw_state = 0x%08x.\n", dev->host_hw_state, dev->me_hw_state); DBG("ME turn on ME_RDY and host turn on H_RDY.\n"); DBG("heci: link layer has been established.\n"); mutex_exit(&dev->device_lock); return (0); }
/** * heci_ioctl - the IOCTL function * * @file: pointer to file structure * @cmd: ioctl command * @data: pointer to heci message structure * * returns 0 on success , <0 on error */ static long heci_ioctl(struct file *file, unsigned int cmd, unsigned long data) { struct heci_device *dev; struct heci_cl *cl = file->private_data; struct heci_connect_client_data *connect_data = NULL; int rets; dev = cl->dev; dev_dbg(&dev->pdev->dev, "IOCTL cmd = 0x%x", cmd); /* Test API for triggering host-initiated IPC reset to ISH */ if (cmd == 0x12345678) { /* Re-init */ dev->dev_state = HECI_DEV_INITIALIZING; heci_reset(dev, 1); if (heci_hbm_start_wait(dev)) { dev_err(&dev->pdev->dev, "HBM haven't started"); goto err; } if (!heci_host_is_ready(dev)) { dev_err(&dev->pdev->dev, "host is not ready.\n"); goto err; } if (!heci_hw_is_ready(dev)) { dev_err(&dev->pdev->dev, "ME is not ready.\n"); goto err; } return 0; err: dev_err(&dev->pdev->dev, "link layer initialization failed.\n"); dev->dev_state = HECI_DEV_DISABLED; return -ENODEV; } /* Test API for triggering host disabling */ if (cmd == 0xAA55AA55) { /* Handle ISH reset against upper layers */ /* Remove all client devices */ heci_bus_remove_all_clients(dev); dev->dev_state = HECI_DEV_DISABLED; return 0; } if (cmd != IOCTL_HECI_CONNECT_CLIENT) return -EINVAL; if (WARN_ON(!cl || !cl->dev)) return -ENODEV; mutex_lock(&dev->device_lock); if (dev->dev_state != HECI_DEV_ENABLED) { rets = -ENODEV; goto out; } dev_dbg(&dev->pdev->dev, ": IOCTL_HECI_CONNECT_CLIENT.\n"); connect_data = kzalloc(sizeof(struct heci_connect_client_data), GFP_KERNEL); if (!connect_data) { rets = -ENOMEM; goto out; } dev_dbg(&dev->pdev->dev, "copy connect data from user\n"); if (copy_from_user(connect_data, (char __user *)data, sizeof(struct heci_connect_client_data))) { dev_dbg(&dev->pdev->dev, "failed to copy data from userland\n"); rets = -EFAULT; goto out; } rets = heci_ioctl_connect_client(file, connect_data); /* if all is ok, copying the data back to user. */ if (rets) goto out; dev_dbg(&dev->pdev->dev, "copy connect data to user\n"); if (copy_to_user((char __user *)data, connect_data, sizeof(struct heci_connect_client_data))) { dev_dbg(&dev->pdev->dev, "failed to copy data to userland\n"); rets = -EFAULT; goto out; } out: kfree(connect_data); mutex_unlock(&dev->device_lock); return rets; }
static int heci_bh_process_device(struct iamt_heci_device *dev) { struct io_heci_list complete_list; int32_t slots; int rets, isr_pending = 0; struct heci_cb_private *cb_pos = NULL, *cb_next = NULL; struct heci_file_private *file_ext; int bus_message_received = 0; DBG("function called after ISR to handle the interrupt processing.\n"); /* initialize our complete list */ mutex_enter(&dev->device_lock); heci_initialize_list(&complete_list, dev); dev->host_hw_state = read_heci_register(dev, H_CSR); dev->me_hw_state = read_heci_register(dev, ME_CSR_HA); /* check if ME wants a reset */ if (((dev->me_hw_state & ME_RDY_HRA) == 0) && (dev->heci_state != HECI_RESETING) && (dev->heci_state != HECI_INITIALIZING)) { DBG("FW not ready.\n"); heci_reset(dev, 1); mutex_exit(&dev->device_lock); return (0); } /* check if we need to start the dev */ if ((dev->host_hw_state & H_RDY) == 0) { if ((dev->me_hw_state & ME_RDY_HRA) == ME_RDY_HRA) { DBG("we need to start the dev.\n"); dev->host_hw_state |= (H_IE | H_IG | H_RDY); heci_set_csr_register(dev); if (dev->heci_state == HECI_INITIALIZING) { dev->recvd_msg = 1; cv_broadcast(&dev->wait_recvd_msg); mutex_exit(&dev->device_lock); return (0); } else { mutex_exit(&dev->device_lock); if (dev->reinit_tsk && ddi_taskq_dispatch(dev->reinit_tsk, heci_task_initialize_clients, dev, DDI_SLEEP) == DDI_FAILURE) { cmn_err(CE_WARN, "taskq_dispatch " "failed for reinit_tsk"); } return (0); } } else { DBG("enable interrupt FW not ready.\n"); heci_csr_enable_interrupts(dev); mutex_exit(&dev->device_lock); return (0); } } /* check slots avalable for reading */ slots = count_full_read_slots(dev); DBG("slots =%08x extra_write_index =%08x.\n", slots, dev->extra_write_index); while ((slots > 0) && (!dev->extra_write_index)) { DBG("slots =%08x extra_write_index =%08x.\n", slots, dev->extra_write_index); DBG("call heci_bh_read_handler.\n"); rets = heci_bh_read_handler(&complete_list, dev, &slots); if (rets != 0) goto end; } rets = heci_bh_write_handler(&complete_list, dev, &slots); end: DBG("end of bottom half function.\n"); dev->host_hw_state = read_heci_register(dev, H_CSR); dev->host_buffer_is_empty = host_buffer_is_empty(dev); if ((dev->host_hw_state & H_IS) == H_IS) { /* acknowledge interrupt and disable interrupts */ heci_csr_disable_interrupts(dev); DBG("schedule work the heci_bh_handler.\n"); isr_pending = 1; } else { heci_csr_enable_interrupts(dev); } if (dev->recvd_msg) { DBG("received waiting bus message\n"); bus_message_received = 1; } if (bus_message_received) { DBG("wake up dev->wait_recvd_msg\n"); cv_broadcast(&dev->wait_recvd_msg); bus_message_received = 0; } if ((complete_list.status != 0) || list_empty(&complete_list.heci_cb.cb_list)) { mutex_exit(&dev->device_lock); return (isr_pending); } mutex_exit(&dev->device_lock); list_for_each_entry_safe(cb_pos, cb_next, &complete_list.heci_cb.cb_list, cb_list, struct heci_cb_private) { file_ext = (struct heci_file_private *)cb_pos->file_private; list_del(&cb_pos->cb_list); if (file_ext != NULL) { if (file_ext != &dev->iamthif_file_ext) { DBG("completing call back.\n"); _heci_cmpl(file_ext, cb_pos); cb_pos = NULL; } else if (file_ext == &dev->iamthif_file_ext) { _heci_cmpl_iamthif(dev, cb_pos); } } } return (isr_pending); }