Skip to content

Commit

Permalink
net: wwan: iosm: transport layer support for fw flashing/cd
Browse files Browse the repository at this point in the history
Implements transport layer protocol for fw flashing/coredump
collection.

Signed-off-by: M Chetan Kumar <m.chetan.kumar@linux.intel.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
mchetankumar authored and davem330 committed Sep 20, 2021
1 parent 09e7b00 commit 8d9be06
Show file tree
Hide file tree
Showing 6 changed files with 464 additions and 30 deletions.
6 changes: 5 additions & 1 deletion drivers/net/wwan/iosm/iosm_ipc_chnl_cfg.c
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
#include "iosm_ipc_chnl_cfg.h"

/* Max. sizes of a downlink buffers */
#define IPC_MEM_MAX_DL_FLASH_BUF_SIZE (16 * 1024)
#define IPC_MEM_MAX_DL_FLASH_BUF_SIZE (64 * 1024)
#define IPC_MEM_MAX_DL_LOOPBACK_SIZE (1 * 1024 * 1024)
#define IPC_MEM_MAX_DL_AT_BUF_SIZE 2048
#define IPC_MEM_MAX_DL_RPC_BUF_SIZE (32 * 1024)
Expand Down Expand Up @@ -60,6 +60,10 @@ static struct ipc_chnl_cfg modem_cfg[] = {
{ IPC_MEM_CTRL_CHL_ID_6, IPC_MEM_PIPE_12, IPC_MEM_PIPE_13,
IPC_MEM_MAX_TDS_MBIM, IPC_MEM_MAX_TDS_MBIM,
IPC_MEM_MAX_DL_MBIM_BUF_SIZE, WWAN_PORT_MBIM },
/* Flash Channel/Coredump Channel */
{ IPC_MEM_CTRL_CHL_ID_7, IPC_MEM_PIPE_0, IPC_MEM_PIPE_1,
IPC_MEM_MAX_TDS_FLASH_UL, IPC_MEM_MAX_TDS_FLASH_DL,
IPC_MEM_MAX_DL_FLASH_BUF_SIZE, WWAN_PORT_UNKNOWN },
};

int ipc_chnl_cfg_get(struct ipc_chnl_cfg *chnl_cfg, int index)
Expand Down
1 change: 1 addition & 0 deletions drivers/net/wwan/iosm/iosm_ipc_chnl_cfg.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ enum ipc_channel_id {
IPC_MEM_CTRL_CHL_ID_4,
IPC_MEM_CTRL_CHL_ID_5,
IPC_MEM_CTRL_CHL_ID_6,
IPC_MEM_CTRL_CHL_ID_7,
};

/**
Expand Down
103 changes: 78 additions & 25 deletions drivers/net/wwan/iosm/iosm_ipc_imem.c
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
#include <linux/delay.h>

#include "iosm_ipc_chnl_cfg.h"
#include "iosm_ipc_devlink.h"
#include "iosm_ipc_flash.h"
#include "iosm_ipc_imem.h"
#include "iosm_ipc_port.h"

Expand Down Expand Up @@ -263,9 +265,12 @@ static void ipc_imem_dl_skb_process(struct iosm_imem *ipc_imem,
switch (pipe->channel->ctype) {
case IPC_CTYPE_CTRL:
port_id = pipe->channel->channel_id;

/* Pass the packet to the wwan layer. */
wwan_port_rx(ipc_imem->ipc_port[port_id]->iosm_port, skb);
if (port_id == IPC_MEM_CTRL_CHL_ID_7)
ipc_imem_sys_devlink_notify_rx(ipc_imem->ipc_devlink,
skb);
else
wwan_port_rx(ipc_imem->ipc_port[port_id]->iosm_port,
skb);
break;

case IPC_CTYPE_WWAN:
Expand Down Expand Up @@ -399,19 +404,8 @@ static void ipc_imem_rom_irq_exec(struct iosm_imem *ipc_imem)
{
struct ipc_mem_channel *channel;

if (ipc_imem->flash_channel_id < 0) {
ipc_imem->rom_exit_code = IMEM_ROM_EXIT_FAIL;
dev_err(ipc_imem->dev, "Missing flash app:%d",
ipc_imem->flash_channel_id);
return;
}

channel = ipc_imem->ipc_devlink->devlink_sio.channel;
ipc_imem->rom_exit_code = ipc_mmio_get_rom_exit_code(ipc_imem->mmio);

/* Wake up the flash app to continue or to terminate depending
* on the CP ROM exit code.
*/
channel = &ipc_imem->channels[ipc_imem->flash_channel_id];
complete(&channel->ul_sem);
}

Expand Down Expand Up @@ -572,7 +566,7 @@ static void ipc_imem_handle_irq(struct iosm_imem *ipc_imem, int irq)
enum ipc_phase old_phase, phase;
bool retry_allocation = false;
bool ul_pending = false;
int ch_id, i;
int i;

if (irq != IMEM_IRQ_DONT_CARE)
ipc_imem->ev_irq_pending[irq] = false;
Expand Down Expand Up @@ -696,11 +690,8 @@ static void ipc_imem_handle_irq(struct iosm_imem *ipc_imem, int irq)
if ((phase == IPC_P_PSI || phase == IPC_P_EBL) &&
ipc_imem->ipc_requested_state == IPC_MEM_DEVICE_IPC_RUNNING &&
ipc_mmio_get_ipc_state(ipc_imem->mmio) ==
IPC_MEM_DEVICE_IPC_RUNNING &&
ipc_imem->flash_channel_id >= 0) {
/* Wake up the flash app to open the pipes. */
ch_id = ipc_imem->flash_channel_id;
complete(&ipc_imem->channels[ch_id].ul_sem);
IPC_MEM_DEVICE_IPC_RUNNING) {
complete(&ipc_imem->ipc_devlink->devlink_sio.channel->ul_sem);
}

/* Reset the expected CP state. */
Expand Down Expand Up @@ -1176,6 +1167,9 @@ void ipc_imem_cleanup(struct iosm_imem *ipc_imem)
ipc_port_deinit(ipc_imem->ipc_port);
}

if (ipc_imem->ipc_devlink)
ipc_devlink_deinit(ipc_imem->ipc_devlink);

ipc_imem_device_ipc_uninit(ipc_imem);
ipc_imem_channel_reset(ipc_imem);

Expand Down Expand Up @@ -1258,6 +1252,7 @@ struct iosm_imem *ipc_imem_init(struct iosm_pcie *pcie, unsigned int device_id,
void __iomem *mmio, struct device *dev)
{
struct iosm_imem *ipc_imem = kzalloc(sizeof(*pcie->imem), GFP_KERNEL);
enum ipc_mem_exec_stage stage;

if (!ipc_imem)
return NULL;
Expand All @@ -1272,9 +1267,6 @@ struct iosm_imem *ipc_imem_init(struct iosm_pcie *pcie, unsigned int device_id,
ipc_imem->cp_version = 0;
ipc_imem->device_sleep = IPC_HOST_SLEEP_ENTER_SLEEP;

/* Reset the flash channel id. */
ipc_imem->flash_channel_id = -1;

/* Reset the max number of configured channels */
ipc_imem->nr_of_channels = 0;

Expand Down Expand Up @@ -1328,8 +1320,21 @@ struct iosm_imem *ipc_imem_init(struct iosm_pcie *pcie, unsigned int device_id,
goto imem_config_fail;
}

return ipc_imem;
stage = ipc_mmio_get_exec_stage(ipc_imem->mmio);
if (stage == IPC_MEM_EXEC_STAGE_BOOT) {
/* Alloc and Register devlink */
ipc_imem->ipc_devlink = ipc_devlink_init(ipc_imem);
if (!ipc_imem->ipc_devlink) {
dev_err(ipc_imem->dev, "Devlink register failed");
goto imem_config_fail;
}

if (ipc_flash_link_establish(ipc_imem))
goto devlink_channel_fail;
}
return ipc_imem;
devlink_channel_fail:
ipc_devlink_deinit(ipc_imem->ipc_devlink);
imem_config_fail:
hrtimer_cancel(&ipc_imem->td_alloc_timer);
hrtimer_cancel(&ipc_imem->fast_update_timer);
Expand Down Expand Up @@ -1361,3 +1366,51 @@ void ipc_imem_td_update_timer_suspend(struct iosm_imem *ipc_imem, bool suspend)
{
ipc_imem->td_update_timer_suspended = suspend;
}

/* Verify the CP execution state, copy the chip info,
* change the execution phase to ROM
*/
static int ipc_imem_devlink_trigger_chip_info_cb(struct iosm_imem *ipc_imem,
int arg, void *msg,
size_t msgsize)
{
enum ipc_mem_exec_stage stage;
struct sk_buff *skb;
int rc = -EINVAL;
size_t size;

/* Test the CP execution state. */
stage = ipc_mmio_get_exec_stage(ipc_imem->mmio);
if (stage != IPC_MEM_EXEC_STAGE_BOOT) {
dev_err(ipc_imem->dev,
"Execution_stage: expected BOOT, received = %X", stage);
goto trigger_chip_info_fail;
}
/* Allocate a new sk buf for the chip info. */
size = ipc_imem->mmio->chip_info_size;
if (size > IOSM_CHIP_INFO_SIZE_MAX)
goto trigger_chip_info_fail;

skb = ipc_pcie_alloc_local_skb(ipc_imem->pcie, GFP_ATOMIC, size);
if (!skb) {
dev_err(ipc_imem->dev, "exhausted skbuf kernel DL memory");
rc = -ENOMEM;
goto trigger_chip_info_fail;
}
/* Copy the chip info characters into the ipc_skb. */
ipc_mmio_copy_chip_info(ipc_imem->mmio, skb_put(skb, size), size);
/* First change to the ROM boot phase. */
dev_dbg(ipc_imem->dev, "execution_stage[%X] eq. BOOT", stage);
ipc_imem->phase = ipc_imem_phase_update(ipc_imem);
ipc_imem_sys_devlink_notify_rx(ipc_imem->ipc_devlink, skb);
rc = 0;
trigger_chip_info_fail:
return rc;
}

int ipc_imem_devlink_trigger_chip_info(struct iosm_imem *ipc_imem)
{
return ipc_task_queue_send_task(ipc_imem,
ipc_imem_devlink_trigger_chip_info_cb,
0, NULL, 0, true);
}
18 changes: 15 additions & 3 deletions drivers/net/wwan/iosm/iosm_ipc_imem.h
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ struct ipc_chnl_cfg;

#define IMEM_IRQ_DONT_CARE (-1)

#define IPC_MEM_MAX_CHANNELS 7
#define IPC_MEM_MAX_CHANNELS 8

#define IPC_MEM_MUX_IP_SESSION_ENTRIES 8

Expand Down Expand Up @@ -98,6 +98,7 @@ struct ipc_chnl_cfg;
#define IPC_MEM_DL_ETH_OFFSET 16

#define IPC_CB(skb) ((struct ipc_skb_cb *)((skb)->cb))
#define IOSM_CHIP_INFO_SIZE_MAX 100

#define FULLY_FUNCTIONAL 0

Expand Down Expand Up @@ -304,9 +305,9 @@ enum ipc_phase {
* @ipc_port: IPC PORT data structure pointer
* @pcie: IPC PCIe
* @dev: Pointer to device structure
* @flash_channel_id: Reserved channel id for flashing to RAM.
* @ipc_requested_state: Expected IPC state on CP.
* @channels: Channel list with UL/DL pipe pairs.
* @ipc_devlink: IPC Devlink data structure pointer
* @ipc_status: local ipc_status
* @nr_of_channels: number of configured channels
* @startup_timer: startup timer for NAND support.
Expand Down Expand Up @@ -349,9 +350,9 @@ struct iosm_imem {
struct iosm_cdev *ipc_port[IPC_MEM_MAX_CHANNELS];
struct iosm_pcie *pcie;
struct device *dev;
int flash_channel_id;
enum ipc_mem_device_ipc_state ipc_requested_state;
struct ipc_mem_channel channels[IPC_MEM_MAX_CHANNELS];
struct iosm_devlink *ipc_devlink;
u32 ipc_status;
u32 nr_of_channels;
struct hrtimer startup_timer;
Expand Down Expand Up @@ -575,4 +576,15 @@ void ipc_imem_ipc_init_check(struct iosm_imem *ipc_imem);
*/
void ipc_imem_channel_init(struct iosm_imem *ipc_imem, enum ipc_ctype ctype,
struct ipc_chnl_cfg chnl_cfg, u32 irq_moderation);

/**
* ipc_imem_devlink_trigger_chip_info - Inform devlink that the chip
* information are available if the
* flashing to RAM interworking shall be
* executed.
* @ipc_imem: Pointer to imem structure
*
* Returns: 0 on success, -1 on failure
*/
int ipc_imem_devlink_trigger_chip_info(struct iosm_imem *ipc_imem);
#endif

0 comments on commit 8d9be06

Please sign in to comment.