diff options
Diffstat (limited to 'drivers/net/wwan/iosm/iosm_ipc_imem_ops.c')
-rw-r--r-- | drivers/net/wwan/iosm/iosm_ipc_imem_ops.c | 317 |
1 files changed, 0 insertions, 317 deletions
diff --git a/drivers/net/wwan/iosm/iosm_ipc_imem_ops.c b/drivers/net/wwan/iosm/iosm_ipc_imem_ops.c index b885a6570235..0a472ce77370 100644 --- a/drivers/net/wwan/iosm/iosm_ipc_imem_ops.c +++ b/drivers/net/wwan/iosm/iosm_ipc_imem_ops.c @@ -6,7 +6,6 @@ #include <linux/delay.h> #include "iosm_ipc_chnl_cfg.h" -#include "iosm_ipc_devlink.h" #include "iosm_ipc_imem.h" #include "iosm_ipc_imem_ops.h" #include "iosm_ipc_port.h" @@ -332,319 +331,3 @@ int ipc_imem_sys_cdev_write(struct iosm_cdev *ipc_cdev, struct sk_buff *skb) out: return ret; } - -/* Open a SIO link to CP and return the channel instance */ -struct ipc_mem_channel *ipc_imem_sys_devlink_open(struct iosm_imem *ipc_imem) -{ - struct ipc_mem_channel *channel; - enum ipc_phase phase; - int channel_id; - - phase = ipc_imem_phase_update(ipc_imem); - switch (phase) { - case IPC_P_OFF: - case IPC_P_ROM: - /* Get a channel id as flash id and reserve it. */ - channel_id = ipc_imem_channel_alloc(ipc_imem, - IPC_MEM_CTRL_CHL_ID_7, - IPC_CTYPE_CTRL); - - if (channel_id < 0) { - dev_err(ipc_imem->dev, - "reservation of a flash channel id failed"); - goto error; - } - - ipc_imem->ipc_devlink->devlink_sio.channel_id = channel_id; - channel = &ipc_imem->channels[channel_id]; - - /* Enqueue chip info data to be read */ - if (ipc_imem_devlink_trigger_chip_info(ipc_imem)) { - dev_err(ipc_imem->dev, "Enqueue of chip info failed"); - channel->state = IMEM_CHANNEL_FREE; - goto error; - } - - return channel; - - case IPC_P_PSI: - case IPC_P_EBL: - ipc_imem->cp_version = ipc_mmio_get_cp_version(ipc_imem->mmio); - if (ipc_imem->cp_version == -1) { - dev_err(ipc_imem->dev, "invalid CP version"); - goto error; - } - - channel_id = ipc_imem->ipc_devlink->devlink_sio.channel_id; - return ipc_imem_channel_open(ipc_imem, channel_id, - IPC_HP_CDEV_OPEN); - - default: - /* CP is in the wrong state (e.g. CRASH or CD_READY) */ - dev_err(ipc_imem->dev, "SIO open refused, phase %d", phase); - } -error: - return NULL; -} - -/* Release a SIO channel link to CP. */ -void ipc_imem_sys_devlink_close(struct iosm_devlink *ipc_devlink) -{ - struct iosm_imem *ipc_imem = ipc_devlink->pcie->imem; - int boot_check_timeout = BOOT_CHECK_DEFAULT_TIMEOUT; - enum ipc_mem_exec_stage exec_stage; - struct ipc_mem_channel *channel; - enum ipc_phase curr_phase; - int status = 0; - u32 tail = 0; - - channel = ipc_imem->ipc_devlink->devlink_sio.channel; - curr_phase = ipc_imem->phase; - /* Increase the total wait time to boot_check_timeout */ - do { - exec_stage = ipc_mmio_get_exec_stage(ipc_imem->mmio); - if (exec_stage == IPC_MEM_EXEC_STAGE_RUN || - exec_stage == IPC_MEM_EXEC_STAGE_PSI) - break; - msleep(20); - boot_check_timeout -= 20; - } while (boot_check_timeout > 0); - - /* If there are any pending TDs then wait for Timeout/Completion before - * closing pipe. - */ - if (channel->ul_pipe.old_tail != channel->ul_pipe.old_head) { - status = wait_for_completion_interruptible_timeout - (&ipc_imem->ul_pend_sem, - msecs_to_jiffies(IPC_PEND_DATA_TIMEOUT)); - if (status == 0) { - dev_dbg(ipc_imem->dev, - "Data Timeout on UL-Pipe:%d Head:%d Tail:%d", - channel->ul_pipe.pipe_nr, - channel->ul_pipe.old_head, - channel->ul_pipe.old_tail); - } - } - - ipc_protocol_get_head_tail_index(ipc_imem->ipc_protocol, - &channel->dl_pipe, NULL, &tail); - - if (tail != channel->dl_pipe.old_tail) { - status = wait_for_completion_interruptible_timeout - (&ipc_imem->dl_pend_sem, - msecs_to_jiffies(IPC_PEND_DATA_TIMEOUT)); - if (status == 0) { - dev_dbg(ipc_imem->dev, - "Data Timeout on DL-Pipe:%d Head:%d Tail:%d", - channel->dl_pipe.pipe_nr, - channel->dl_pipe.old_head, - channel->dl_pipe.old_tail); - } - } - - /* Due to wait for completion in messages, there is a small window - * between closing the pipe and updating the channel is closed. In this - * small window there could be HP update from Host Driver. Hence update - * the channel state as CLOSING to aviod unnecessary interrupt - * towards CP. - */ - channel->state = IMEM_CHANNEL_CLOSING; - /* Release the pipe resources */ - ipc_imem_pipe_cleanup(ipc_imem, &channel->ul_pipe); - ipc_imem_pipe_cleanup(ipc_imem, &channel->dl_pipe); -} - -void ipc_imem_sys_devlink_notify_rx(struct iosm_devlink *ipc_devlink, - struct sk_buff *skb) -{ - skb_queue_tail(&ipc_devlink->devlink_sio.rx_list, skb); - complete(&ipc_devlink->devlink_sio.read_sem); -} - -/* PSI transfer */ -static int ipc_imem_sys_psi_transfer(struct iosm_imem *ipc_imem, - struct ipc_mem_channel *channel, - unsigned char *buf, int count) -{ - int psi_start_timeout = PSI_START_DEFAULT_TIMEOUT; - enum ipc_mem_exec_stage exec_stage; - - dma_addr_t mapping = 0; - int ret; - - ret = ipc_pcie_addr_map(ipc_imem->pcie, buf, count, &mapping, - DMA_TO_DEVICE); - if (ret) - goto pcie_addr_map_fail; - - /* Save the PSI information for the CP ROM driver on the doorbell - * scratchpad. - */ - ipc_mmio_set_psi_addr_and_size(ipc_imem->mmio, mapping, count); - ipc_doorbell_fire(ipc_imem->pcie, 0, IPC_MEM_EXEC_STAGE_BOOT); - - ret = wait_for_completion_interruptible_timeout - (&channel->ul_sem, - msecs_to_jiffies(IPC_PSI_TRANSFER_TIMEOUT)); - - if (ret <= 0) { - dev_err(ipc_imem->dev, "Failed PSI transfer to CP, Error-%d", - ret); - goto psi_transfer_fail; - } - /* If the PSI download fails, return the CP boot ROM exit code */ - if (ipc_imem->rom_exit_code != IMEM_ROM_EXIT_OPEN_EXT && - ipc_imem->rom_exit_code != IMEM_ROM_EXIT_CERT_EXT) { - ret = (-1) * ((int)ipc_imem->rom_exit_code); - goto psi_transfer_fail; - } - - dev_dbg(ipc_imem->dev, "PSI image successfully downloaded"); - - /* Wait psi_start_timeout milliseconds until the CP PSI image is - * running and updates the execution_stage field with - * IPC_MEM_EXEC_STAGE_PSI. Verify the execution stage. - */ - do { - exec_stage = ipc_mmio_get_exec_stage(ipc_imem->mmio); - - if (exec_stage == IPC_MEM_EXEC_STAGE_PSI) - break; - - msleep(20); - psi_start_timeout -= 20; - } while (psi_start_timeout > 0); - - if (exec_stage != IPC_MEM_EXEC_STAGE_PSI) - goto psi_transfer_fail; /* Unknown status of CP PSI process. */ - - ipc_imem->phase = IPC_P_PSI; - - /* Enter the PSI phase. */ - dev_dbg(ipc_imem->dev, "execution_stage[%X] eq. PSI", exec_stage); - - /* Request the RUNNING state from CP and wait until it was reached - * or timeout. - */ - ipc_imem_ipc_init_check(ipc_imem); - - ret = wait_for_completion_interruptible_timeout - (&channel->ul_sem, msecs_to_jiffies(IPC_PSI_TRANSFER_TIMEOUT)); - if (ret <= 0) { - dev_err(ipc_imem->dev, - "Failed PSI RUNNING state on CP, Error-%d", ret); - goto psi_transfer_fail; - } - - if (ipc_mmio_get_ipc_state(ipc_imem->mmio) != - IPC_MEM_DEVICE_IPC_RUNNING) { - dev_err(ipc_imem->dev, - "ch[%d] %s: unexpected CP IPC state %d, not RUNNING", - channel->channel_id, - ipc_imem_phase_get_string(ipc_imem->phase), - ipc_mmio_get_ipc_state(ipc_imem->mmio)); - - goto psi_transfer_fail; - } - - /* Create the flash channel for the transfer of the images. */ - if (!ipc_imem_sys_devlink_open(ipc_imem)) { - dev_err(ipc_imem->dev, "can't open flash_channel"); - goto psi_transfer_fail; - } - - ret = 0; -psi_transfer_fail: - ipc_pcie_addr_unmap(ipc_imem->pcie, count, mapping, DMA_TO_DEVICE); -pcie_addr_map_fail: - return ret; -} - -int ipc_imem_sys_devlink_write(struct iosm_devlink *ipc_devlink, - unsigned char *buf, int count) -{ - struct iosm_imem *ipc_imem = ipc_devlink->pcie->imem; - struct ipc_mem_channel *channel; - struct sk_buff *skb; - dma_addr_t mapping; - int ret; - - channel = ipc_imem->ipc_devlink->devlink_sio.channel; - - /* In the ROM phase the PSI image is passed to CP about a specific - * shared memory area and doorbell scratchpad directly. - */ - if (ipc_imem->phase == IPC_P_ROM) { - ret = ipc_imem_sys_psi_transfer(ipc_imem, channel, buf, count); - /* If the PSI transfer fails then send crash - * Signature. - */ - if (ret > 0) - ipc_imem_msg_send_feature_set(ipc_imem, - IPC_MEM_INBAND_CRASH_SIG, - false); - goto out; - } - - /* Allocate skb memory for the uplink buffer. */ - skb = ipc_pcie_alloc_skb(ipc_devlink->pcie, count, GFP_KERNEL, &mapping, - DMA_TO_DEVICE, 0); - if (!skb) { - ret = -ENOMEM; - goto out; - } - - memcpy(skb_put(skb, count), buf, count); - - IPC_CB(skb)->op_type = UL_USR_OP_BLOCKED; - - /* Add skb to the uplink skbuf accumulator. */ - skb_queue_tail(&channel->ul_list, skb); - - /* Inform the IPC tasklet to pass uplink IP packets to CP. */ - if (!ipc_imem_call_cdev_write(ipc_imem)) { - ret = wait_for_completion_interruptible(&channel->ul_sem); - - if (ret < 0) { - dev_err(ipc_imem->dev, - "ch[%d] no CP confirmation, status = %d", - channel->channel_id, ret); - ipc_pcie_kfree_skb(ipc_devlink->pcie, skb); - goto out; - } - } - ret = 0; -out: - return ret; -} - -int ipc_imem_sys_devlink_read(struct iosm_devlink *devlink, u8 *data, - u32 bytes_to_read, u32 *bytes_read) -{ - struct sk_buff *skb = NULL; - int rc = 0; - - /* check skb is available in rx_list or wait for skb */ - devlink->devlink_sio.devlink_read_pend = 1; - while (!skb && !(skb = skb_dequeue(&devlink->devlink_sio.rx_list))) { - if (!wait_for_completion_interruptible_timeout - (&devlink->devlink_sio.read_sem, - msecs_to_jiffies(IPC_READ_TIMEOUT))) { - dev_err(devlink->dev, "Read timedout"); - rc = -ETIMEDOUT; - goto devlink_read_fail; - } - } - devlink->devlink_sio.devlink_read_pend = 0; - if (bytes_to_read < skb->len) { - dev_err(devlink->dev, "Invalid size,expected len %d", skb->len); - rc = -EINVAL; - goto devlink_read_fail; - } - *bytes_read = skb->len; - memcpy(data, skb->data, skb->len); - -devlink_read_fail: - ipc_pcie_kfree_skb(devlink->pcie, skb); - return rc; -} |