Merge 561bed688b ("Merge git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net") into android-mainline

Steps on the way to 5.16-rc1

Signed-off-by: Greg Kroah-Hartman <gregkh@google.com>
Change-Id: Ied3c17003accdafdb4871fa5163557ca074de55e
This commit is contained in:
Greg Kroah-Hartman
2021-11-08 14:35:26 +01:00
40 changed files with 562 additions and 2129 deletions

View File

@@ -151,10 +151,9 @@ int arc_mdio_probe(struct arc_emac_priv *priv)
data->reset_gpio = devm_gpiod_get_optional(priv->dev, "phy-reset",
GPIOD_OUT_LOW);
if (IS_ERR(data->reset_gpio)) {
error = PTR_ERR(data->reset_gpio);
dev_err(priv->dev, "Failed to request gpio: %d\n", error);
mdiobus_free(bus);
return error;
return dev_err_probe(priv->dev, PTR_ERR(data->reset_gpio),
"Failed to request gpio\n");
}
of_property_read_u32(np, "phy-reset-duration", &data->msec);
@@ -166,9 +165,9 @@ int arc_mdio_probe(struct arc_emac_priv *priv)
error = of_mdiobus_register(bus, priv->dev->of_node);
if (error) {
dev_err(priv->dev, "cannot register MDIO bus %s\n", bus->name);
mdiobus_free(bus);
return error;
return dev_err_probe(priv->dev, error,
"cannot register MDIO bus %s\n", bus->name);
}
return 0;

View File

@@ -2662,10 +2662,8 @@ static int atl1c_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
/* enable device (incl. PCI PM wakeup and hotplug setup) */
err = pci_enable_device_mem(pdev);
if (err) {
dev_err(&pdev->dev, "cannot enable PCI device\n");
return err;
}
if (err)
return dev_err_probe(&pdev->dev, err, "cannot enable PCI device\n");
/*
* The atl1c chip can DMA to 64-bit addresses, but it uses a single

View File

@@ -2297,10 +2297,8 @@ static int atl1e_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
int err = 0;
err = pci_enable_device(pdev);
if (err) {
dev_err(&pdev->dev, "cannot enable PCI device\n");
return err;
}
if (err)
return dev_err_probe(&pdev->dev, err, "cannot enable PCI device\n");
/*
* The atl1e chip can DMA to 64-bit addresses, but it uses a single

View File

@@ -1311,9 +1311,8 @@ static int nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
err = pci_enable_device(pdev);
if (err) {
dev_err(dev, "Failed to enable PCI device\n");
pci_set_drvdata(pdev, NULL);
return err;
return dev_err_probe(dev, err, "Failed to enable PCI device\n");
}
err = pci_request_regions(pdev, DRV_NAME);

View File

@@ -2119,10 +2119,8 @@ static int nicvf_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
}
err = pci_enable_device(pdev);
if (err) {
dev_err(dev, "Failed to enable PCI device\n");
return err;
}
if (err)
return dev_err_probe(dev, err, "Failed to enable PCI device\n");
err = pci_request_regions(pdev, DRV_NAME);
if (err) {

View File

@@ -1597,9 +1597,8 @@ static int bgx_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
err = pcim_enable_device(pdev);
if (err) {
dev_err(dev, "Failed to enable PCI device\n");
pci_set_drvdata(pdev, NULL);
return err;
return dev_err_probe(dev, err, "Failed to enable PCI device\n");
}
err = pci_request_regions(pdev, DRV_NAME);

View File

@@ -2902,10 +2902,8 @@ static int cxgb4vf_pci_probe(struct pci_dev *pdev,
* Initialize generic PCI device state.
*/
err = pci_enable_device(pdev);
if (err) {
dev_err(&pdev->dev, "cannot enable PCI device\n");
return err;
}
if (err)
return dev_err_probe(&pdev->dev, err, "cannot enable PCI device\n");
/*
* Reserve PCI resources for the device. If we can't get them some

View File

@@ -707,20 +707,16 @@ static int ethoc_mdio_probe(struct net_device *dev)
else
phy = phy_find_first(priv->mdio);
if (!phy) {
dev_err(&dev->dev, "no PHY found\n");
return -ENXIO;
}
if (!phy)
return dev_err_probe(&dev->dev, -ENXIO, "no PHY found\n");
priv->old_duplex = -1;
priv->old_link = -1;
err = phy_connect_direct(dev, phy, ethoc_mdio_poll,
PHY_INTERFACE_MODE_GMII);
if (err) {
dev_err(&dev->dev, "could not attach to PHY\n");
return err;
}
if (err)
return dev_err_probe(&dev->dev, err, "could not attach to PHY\n");
phy_set_max_speed(phy, SPEED_100);

View File

@@ -2607,10 +2607,8 @@ int enetc_pci_probe(struct pci_dev *pdev, const char *name, int sizeof_priv)
pcie_flr(pdev);
err = pci_enable_device_mem(pdev);
if (err) {
dev_err(&pdev->dev, "device enable failed\n");
return err;
}
if (err)
return dev_err_probe(&pdev->dev, err, "device enable failed\n");
/* set up for high or low dma */
err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64));

View File

@@ -806,10 +806,8 @@ static int enetc_mdio_probe(struct enetc_pf *pf, struct device_node *np)
snprintf(bus->id, MII_BUS_ID_SIZE, "%s", dev_name(dev));
err = of_mdiobus_register(bus, np);
if (err) {
dev_err(dev, "cannot register MDIO bus\n");
return err;
}
if (err)
return dev_err_probe(dev, err, "cannot register MDIO bus\n");
pf->mdio = bus;
@@ -1218,10 +1216,8 @@ static int enetc_pf_probe(struct pci_dev *pdev,
ERR_PTR(err));
err = enetc_pci_probe(pdev, KBUILD_MODNAME, sizeof(*pf));
if (err) {
dev_err(&pdev->dev, "PCI probing failed\n");
return err;
}
if (err)
return dev_err_probe(&pdev->dev, err, "PCI probing failed\n");
si = pci_get_drvdata(pdev);
if (!si->hw.port || !si->hw.global) {

View File

@@ -39,10 +39,8 @@ static int enetc_ptp_probe(struct pci_dev *pdev,
}
err = pci_enable_device_mem(pdev);
if (err) {
dev_err(&pdev->dev, "device enable failed\n");
return err;
}
if (err)
return dev_err_probe(&pdev->dev, err, "device enable failed\n");
/* set up for high or low dma */
err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64));

View File

@@ -143,10 +143,8 @@ static int enetc_vf_probe(struct pci_dev *pdev,
int err;
err = enetc_pci_probe(pdev, KBUILD_MODNAME, 0);
if (err) {
dev_err(&pdev->dev, "PCI probing failed\n");
return err;
}
if (err)
return dev_err_probe(&pdev->dev, err, "PCI probing failed\n");
si = pci_get_drvdata(pdev);

View File

@@ -1379,10 +1379,8 @@ static int hinic_probe(struct pci_dev *pdev,
{
int err = pci_enable_device(pdev);
if (err) {
dev_err(&pdev->dev, "Failed to enable PCI device\n");
return err;
}
if (err)
return dev_err_probe(&pdev->dev, err, "Failed to enable PCI device\n");
err = pci_request_regions(pdev, HINIC_DRV_NAME);
if (err) {

View File

@@ -191,6 +191,7 @@ enum nix_scheduler {
#define NIX_CHAN_SDP_CH_START (0x700ull)
#define NIX_CHAN_SDP_CHX(a) (NIX_CHAN_SDP_CH_START + (a))
#define NIX_CHAN_SDP_NUM_CHANS 256
#define NIX_CHAN_CPT_CH_START (0x800ull)
/* The mask is to extract lower 10-bits of channel number
* which CPT will pass to X2P.

View File

@@ -186,6 +186,8 @@ M(CPT_LF_ALLOC, 0xA00, cpt_lf_alloc, cpt_lf_alloc_req_msg, \
M(CPT_LF_FREE, 0xA01, cpt_lf_free, msg_req, msg_rsp) \
M(CPT_RD_WR_REGISTER, 0xA02, cpt_rd_wr_register, cpt_rd_wr_reg_msg, \
cpt_rd_wr_reg_msg) \
M(CPT_INLINE_IPSEC_CFG, 0xA04, cpt_inline_ipsec_cfg, \
cpt_inline_ipsec_cfg_msg, msg_rsp) \
M(CPT_STATS, 0xA05, cpt_sts, cpt_sts_req, cpt_sts_rsp) \
M(CPT_RXC_TIME_CFG, 0xA06, cpt_rxc_time_cfg, cpt_rxc_time_cfg_req, \
msg_rsp) \
@@ -270,6 +272,10 @@ M(NIX_BP_ENABLE, 0x8016, nix_bp_enable, nix_bp_cfg_req, \
nix_bp_cfg_rsp) \
M(NIX_BP_DISABLE, 0x8017, nix_bp_disable, nix_bp_cfg_req, msg_rsp) \
M(NIX_GET_MAC_ADDR, 0x8018, nix_get_mac_addr, msg_req, nix_get_mac_addr_rsp) \
M(NIX_INLINE_IPSEC_CFG, 0x8019, nix_inline_ipsec_cfg, \
nix_inline_ipsec_cfg, msg_rsp) \
M(NIX_INLINE_IPSEC_LF_CFG, 0x801a, nix_inline_ipsec_lf_cfg, \
nix_inline_ipsec_lf_cfg, msg_rsp) \
M(NIX_CN10K_AQ_ENQ, 0x801b, nix_cn10k_aq_enq, nix_cn10k_aq_enq_req, \
nix_cn10k_aq_enq_rsp) \
M(NIX_GET_HW_INFO, 0x801c, nix_get_hw_info, msg_req, nix_hw_info) \
@@ -1065,6 +1071,40 @@ struct nix_bp_cfg_rsp {
u8 chan_cnt; /* Number of channel for which bpids are assigned */
};
/* Global NIX inline IPSec configuration */
struct nix_inline_ipsec_cfg {
struct mbox_msghdr hdr;
u32 cpt_credit;
struct {
u8 egrp;
u8 opcode;
u16 param1;
u16 param2;
} gen_cfg;
struct {
u16 cpt_pf_func;
u8 cpt_slot;
} inst_qsel;
u8 enable;
};
/* Per NIX LF inline IPSec configuration */
struct nix_inline_ipsec_lf_cfg {
struct mbox_msghdr hdr;
u64 sa_base_addr;
struct {
u32 tag_const;
u16 lenm1_max;
u8 sa_pow2_size;
u8 tt;
} ipsec_cfg0;
struct {
u32 sa_idx_max;
u8 sa_idx_w;
} ipsec_cfg1;
u8 enable;
};
struct nix_hw_info {
struct mbox_msghdr hdr;
u16 rsvs16;
@@ -1399,7 +1439,9 @@ enum cpt_af_status {
CPT_AF_ERR_LF_INVALID = -903,
CPT_AF_ERR_ACCESS_DENIED = -904,
CPT_AF_ERR_SSO_PF_FUNC_INVALID = -905,
CPT_AF_ERR_NIX_PF_FUNC_INVALID = -906
CPT_AF_ERR_NIX_PF_FUNC_INVALID = -906,
CPT_AF_ERR_INLINE_IPSEC_INB_ENA = -907,
CPT_AF_ERR_INLINE_IPSEC_OUT_ENA = -908
};
/* CPT mbox message formats */
@@ -1420,6 +1462,22 @@ struct cpt_lf_alloc_req_msg {
int blkaddr;
};
#define CPT_INLINE_INBOUND 0
#define CPT_INLINE_OUTBOUND 1
/* Mailbox message request format for CPT IPsec
* inline inbound and outbound configuration.
*/
struct cpt_inline_ipsec_cfg_msg {
struct mbox_msghdr hdr;
u8 enable;
u8 slot;
u8 dir;
u8 sso_pf_func_ovrd;
u16 sso_pf_func; /* inbound path SSO_PF_FUNC */
u16 nix_pf_func; /* outbound path NIX_PF_FUNC */
};
/* Mailbox message request and response format for CPT stats. */
struct cpt_sts_req {
struct mbox_msghdr hdr;

View File

@@ -1287,6 +1287,60 @@ static int rvu_lookup_rsrc(struct rvu *rvu, struct rvu_block *block,
return (val & 0xFFF);
}
int rvu_get_blkaddr_from_slot(struct rvu *rvu, int blktype, u16 pcifunc,
u16 global_slot, u16 *slot_in_block)
{
struct rvu_pfvf *pfvf = rvu_get_pfvf(rvu, pcifunc);
int numlfs, total_lfs = 0, nr_blocks = 0;
int i, num_blkaddr[BLK_COUNT] = { 0 };
struct rvu_block *block;
int blkaddr = -ENODEV;
u16 start_slot;
if (!is_blktype_attached(pfvf, blktype))
return -ENODEV;
/* Get all the block addresses from which LFs are attached to
* the given pcifunc in num_blkaddr[].
*/
for (blkaddr = BLKADDR_RVUM; blkaddr < BLK_COUNT; blkaddr++) {
block = &rvu->hw->block[blkaddr];
if (block->type != blktype)
continue;
if (!is_block_implemented(rvu->hw, blkaddr))
continue;
numlfs = rvu_get_rsrc_mapcount(pfvf, blkaddr);
if (numlfs) {
total_lfs += numlfs;
num_blkaddr[nr_blocks] = blkaddr;
nr_blocks++;
}
}
if (global_slot >= total_lfs)
return -ENODEV;
/* Based on the given global slot number retrieve the
* correct block address out of all attached block
* addresses and slot number in that block.
*/
total_lfs = 0;
blkaddr = -ENODEV;
for (i = 0; i < nr_blocks; i++) {
numlfs = rvu_get_rsrc_mapcount(pfvf, num_blkaddr[i]);
total_lfs += numlfs;
if (global_slot < total_lfs) {
blkaddr = num_blkaddr[i];
start_slot = total_lfs - numlfs;
*slot_in_block = global_slot - start_slot;
break;
}
}
return blkaddr;
}
static void rvu_detach_block(struct rvu *rvu, int pcifunc, int blktype)
{
struct rvu_pfvf *pfvf = rvu_get_pfvf(rvu, pcifunc);

View File

@@ -656,6 +656,8 @@ int rvu_lf_reset(struct rvu *rvu, struct rvu_block *block, int lf);
int rvu_get_blkaddr(struct rvu *rvu, int blktype, u16 pcifunc);
int rvu_poll_reg(struct rvu *rvu, u64 block, u64 offset, u64 mask, bool zero);
int rvu_get_num_lbk_chans(void);
int rvu_get_blkaddr_from_slot(struct rvu *rvu, int blktype, u16 pcifunc,
u16 global_slot, u16 *slot_in_block);
/* RVU HW reg validation */
enum regmap_block {

View File

@@ -334,8 +334,8 @@ int rvu_set_channels_base(struct rvu *rvu)
/* Out of 4096 channels start CPT from 2048 so
* that MSB for CPT channels is always set
*/
if (cpt_chan_base <= 0x800) {
hw->cpt_chan_base = 0x800;
if (cpt_chan_base <= NIX_CHAN_CPT_CH_START) {
hw->cpt_chan_base = NIX_CHAN_CPT_CH_START;
} else {
dev_err(rvu->dev,
"CPT channels could not fit in the range 2048-4095\n");

View File

@@ -197,6 +197,141 @@ int rvu_mbox_handler_cpt_lf_free(struct rvu *rvu, struct msg_req *req,
return ret;
}
static int cpt_inline_ipsec_cfg_inbound(struct rvu *rvu, int blkaddr, u8 cptlf,
struct cpt_inline_ipsec_cfg_msg *req)
{
u16 sso_pf_func = req->sso_pf_func;
u8 nix_sel;
u64 val;
val = rvu_read64(rvu, blkaddr, CPT_AF_LFX_CTL(cptlf));
if (req->enable && (val & BIT_ULL(16))) {
/* IPSec inline outbound path is already enabled for a given
* CPT LF, HRM states that inline inbound & outbound paths
* must not be enabled at the same time for a given CPT LF
*/
return CPT_AF_ERR_INLINE_IPSEC_INB_ENA;
}
/* Check if requested 'CPTLF <=> SSOLF' mapping is valid */
if (sso_pf_func && !is_pffunc_map_valid(rvu, sso_pf_func, BLKTYPE_SSO))
return CPT_AF_ERR_SSO_PF_FUNC_INVALID;
nix_sel = (blkaddr == BLKADDR_CPT1) ? 1 : 0;
/* Enable CPT LF for IPsec inline inbound operations */
if (req->enable)
val |= BIT_ULL(9);
else
val &= ~BIT_ULL(9);
val |= (u64)nix_sel << 8;
rvu_write64(rvu, blkaddr, CPT_AF_LFX_CTL(cptlf), val);
if (sso_pf_func) {
/* Set SSO_PF_FUNC */
val = rvu_read64(rvu, blkaddr, CPT_AF_LFX_CTL2(cptlf));
val |= (u64)sso_pf_func << 32;
val |= (u64)req->nix_pf_func << 48;
rvu_write64(rvu, blkaddr, CPT_AF_LFX_CTL2(cptlf), val);
}
if (req->sso_pf_func_ovrd)
/* Set SSO_PF_FUNC_OVRD for inline IPSec */
rvu_write64(rvu, blkaddr, CPT_AF_ECO, 0x1);
/* Configure the X2P Link register with the cpt base channel number and
* range of channels it should propagate to X2P
*/
if (!is_rvu_otx2(rvu)) {
val = (ilog2(NIX_CHAN_CPT_X2P_MASK + 1) << 16);
val |= rvu->hw->cpt_chan_base;
rvu_write64(rvu, blkaddr, CPT_AF_X2PX_LINK_CFG(0), val);
rvu_write64(rvu, blkaddr, CPT_AF_X2PX_LINK_CFG(1), val);
}
return 0;
}
static int cpt_inline_ipsec_cfg_outbound(struct rvu *rvu, int blkaddr, u8 cptlf,
struct cpt_inline_ipsec_cfg_msg *req)
{
u16 nix_pf_func = req->nix_pf_func;
int nix_blkaddr;
u8 nix_sel;
u64 val;
val = rvu_read64(rvu, blkaddr, CPT_AF_LFX_CTL(cptlf));
if (req->enable && (val & BIT_ULL(9))) {
/* IPSec inline inbound path is already enabled for a given
* CPT LF, HRM states that inline inbound & outbound paths
* must not be enabled at the same time for a given CPT LF
*/
return CPT_AF_ERR_INLINE_IPSEC_OUT_ENA;
}
/* Check if requested 'CPTLF <=> NIXLF' mapping is valid */
if (nix_pf_func && !is_pffunc_map_valid(rvu, nix_pf_func, BLKTYPE_NIX))
return CPT_AF_ERR_NIX_PF_FUNC_INVALID;
/* Enable CPT LF for IPsec inline outbound operations */
if (req->enable)
val |= BIT_ULL(16);
else
val &= ~BIT_ULL(16);
rvu_write64(rvu, blkaddr, CPT_AF_LFX_CTL(cptlf), val);
if (nix_pf_func) {
/* Set NIX_PF_FUNC */
val = rvu_read64(rvu, blkaddr, CPT_AF_LFX_CTL2(cptlf));
val |= (u64)nix_pf_func << 48;
rvu_write64(rvu, blkaddr, CPT_AF_LFX_CTL2(cptlf), val);
nix_blkaddr = rvu_get_blkaddr(rvu, BLKTYPE_NIX, nix_pf_func);
nix_sel = (nix_blkaddr == BLKADDR_NIX0) ? 0 : 1;
val = rvu_read64(rvu, blkaddr, CPT_AF_LFX_CTL(cptlf));
val |= (u64)nix_sel << 8;
rvu_write64(rvu, blkaddr, CPT_AF_LFX_CTL(cptlf), val);
}
return 0;
}
int rvu_mbox_handler_cpt_inline_ipsec_cfg(struct rvu *rvu,
struct cpt_inline_ipsec_cfg_msg *req,
struct msg_rsp *rsp)
{
u16 pcifunc = req->hdr.pcifunc;
struct rvu_block *block;
int cptlf, blkaddr, ret;
u16 actual_slot;
blkaddr = rvu_get_blkaddr_from_slot(rvu, BLKTYPE_CPT, pcifunc,
req->slot, &actual_slot);
if (blkaddr < 0)
return CPT_AF_ERR_LF_INVALID;
block = &rvu->hw->block[blkaddr];
cptlf = rvu_get_lf(rvu, block, pcifunc, actual_slot);
if (cptlf < 0)
return CPT_AF_ERR_LF_INVALID;
switch (req->dir) {
case CPT_INLINE_INBOUND:
ret = cpt_inline_ipsec_cfg_inbound(rvu, blkaddr, cptlf, req);
break;
case CPT_INLINE_OUTBOUND:
ret = cpt_inline_ipsec_cfg_outbound(rvu, blkaddr, cptlf, req);
break;
default:
return CPT_AF_ERR_PARAM;
}
return ret;
}
static bool is_valid_offset(struct rvu *rvu, struct cpt_rd_wr_reg_msg *req)
{
u64 offset = req->reg_offset;

View File

@@ -4582,6 +4582,118 @@ int rvu_mbox_handler_nix_lso_format_cfg(struct rvu *rvu,
return 0;
}
#define IPSEC_GEN_CFG_EGRP GENMASK_ULL(50, 48)
#define IPSEC_GEN_CFG_OPCODE GENMASK_ULL(47, 32)
#define IPSEC_GEN_CFG_PARAM1 GENMASK_ULL(31, 16)
#define IPSEC_GEN_CFG_PARAM2 GENMASK_ULL(15, 0)
#define CPT_INST_QSEL_BLOCK GENMASK_ULL(28, 24)
#define CPT_INST_QSEL_PF_FUNC GENMASK_ULL(23, 8)
#define CPT_INST_QSEL_SLOT GENMASK_ULL(7, 0)
static void nix_inline_ipsec_cfg(struct rvu *rvu, struct nix_inline_ipsec_cfg *req,
int blkaddr)
{
u8 cpt_idx, cpt_blkaddr;
u64 val;
cpt_idx = (blkaddr == BLKADDR_NIX0) ? 0 : 1;
if (req->enable) {
/* Enable context prefetching */
if (!is_rvu_otx2(rvu))
val = BIT_ULL(51);
/* Set OPCODE and EGRP */
val |= FIELD_PREP(IPSEC_GEN_CFG_EGRP, req->gen_cfg.egrp);
val |= FIELD_PREP(IPSEC_GEN_CFG_OPCODE, req->gen_cfg.opcode);
val |= FIELD_PREP(IPSEC_GEN_CFG_PARAM1, req->gen_cfg.param1);
val |= FIELD_PREP(IPSEC_GEN_CFG_PARAM2, req->gen_cfg.param2);
rvu_write64(rvu, blkaddr, NIX_AF_RX_IPSEC_GEN_CFG, val);
/* Set CPT queue for inline IPSec */
val = FIELD_PREP(CPT_INST_QSEL_SLOT, req->inst_qsel.cpt_slot);
val |= FIELD_PREP(CPT_INST_QSEL_PF_FUNC,
req->inst_qsel.cpt_pf_func);
if (!is_rvu_otx2(rvu)) {
cpt_blkaddr = (cpt_idx == 0) ? BLKADDR_CPT0 :
BLKADDR_CPT1;
val |= FIELD_PREP(CPT_INST_QSEL_BLOCK, cpt_blkaddr);
}
rvu_write64(rvu, blkaddr, NIX_AF_RX_CPTX_INST_QSEL(cpt_idx),
val);
/* Set CPT credit */
rvu_write64(rvu, blkaddr, NIX_AF_RX_CPTX_CREDIT(cpt_idx),
req->cpt_credit);
} else {
rvu_write64(rvu, blkaddr, NIX_AF_RX_IPSEC_GEN_CFG, 0x0);
rvu_write64(rvu, blkaddr, NIX_AF_RX_CPTX_INST_QSEL(cpt_idx),
0x0);
rvu_write64(rvu, blkaddr, NIX_AF_RX_CPTX_CREDIT(cpt_idx),
0x3FFFFF);
}
}
int rvu_mbox_handler_nix_inline_ipsec_cfg(struct rvu *rvu,
struct nix_inline_ipsec_cfg *req,
struct msg_rsp *rsp)
{
if (!is_block_implemented(rvu->hw, BLKADDR_CPT0))
return 0;
nix_inline_ipsec_cfg(rvu, req, BLKADDR_NIX0);
if (is_block_implemented(rvu->hw, BLKADDR_CPT1))
nix_inline_ipsec_cfg(rvu, req, BLKADDR_NIX1);
return 0;
}
int rvu_mbox_handler_nix_inline_ipsec_lf_cfg(struct rvu *rvu,
struct nix_inline_ipsec_lf_cfg *req,
struct msg_rsp *rsp)
{
int lf, blkaddr, err;
u64 val;
if (!is_block_implemented(rvu->hw, BLKADDR_CPT0))
return 0;
err = nix_get_nixlf(rvu, req->hdr.pcifunc, &lf, &blkaddr);
if (err)
return err;
if (req->enable) {
/* Set TT, TAG_CONST, SA_POW2_SIZE and LENM1_MAX */
val = (u64)req->ipsec_cfg0.tt << 44 |
(u64)req->ipsec_cfg0.tag_const << 20 |
(u64)req->ipsec_cfg0.sa_pow2_size << 16 |
req->ipsec_cfg0.lenm1_max;
if (blkaddr == BLKADDR_NIX1)
val |= BIT_ULL(46);
rvu_write64(rvu, blkaddr, NIX_AF_LFX_RX_IPSEC_CFG0(lf), val);
/* Set SA_IDX_W and SA_IDX_MAX */
val = (u64)req->ipsec_cfg1.sa_idx_w << 32 |
req->ipsec_cfg1.sa_idx_max;
rvu_write64(rvu, blkaddr, NIX_AF_LFX_RX_IPSEC_CFG1(lf), val);
/* Set SA base address */
rvu_write64(rvu, blkaddr, NIX_AF_LFX_RX_IPSEC_SA_BASE(lf),
req->sa_base_addr);
} else {
rvu_write64(rvu, blkaddr, NIX_AF_LFX_RX_IPSEC_CFG0(lf), 0x0);
rvu_write64(rvu, blkaddr, NIX_AF_LFX_RX_IPSEC_CFG1(lf), 0x0);
rvu_write64(rvu, blkaddr, NIX_AF_LFX_RX_IPSEC_SA_BASE(lf),
0x0);
}
return 0;
}
void rvu_nix_reset_mac(struct rvu_pfvf *pfvf, int pcifunc)
{
bool from_vf = !!(pcifunc & RVU_PFVF_FUNC_MASK);

View File

@@ -236,6 +236,8 @@
#define NIX_AF_RX_DEF_OIP6_DSCP (0x02F8)
#define NIX_AF_RX_IPSEC_GEN_CFG (0x0300)
#define NIX_AF_RX_CPTX_INST_ADDR (0x0310)
#define NIX_AF_RX_CPTX_INST_QSEL(a) (0x0320ull | (uint64_t)(a) << 3)
#define NIX_AF_RX_CPTX_CREDIT(a) (0x0360ull | (uint64_t)(a) << 3)
#define NIX_AF_NDC_TX_SYNC (0x03F0)
#define NIX_AF_AQ_CFG (0x0400)
#define NIX_AF_AQ_BASE (0x0410)

View File

@@ -223,6 +223,7 @@ struct otx2_hw {
#define HW_TSO 0
#define CN10K_MBOX 1
#define CN10K_LMTST 2
#define CN10K_RPM 3
unsigned long cap_flag;
#define LMT_LINE_SIZE 128
@@ -452,6 +453,7 @@ static inline void otx2_setup_dev_hw_settings(struct otx2_nic *pfvf)
if (!is_dev_otx2(pfvf->pdev)) {
__set_bit(CN10K_MBOX, &hw->cap_flag);
__set_bit(CN10K_LMTST, &hw->cap_flag);
__set_bit(CN10K_RPM, &hw->cap_flag);
}
}

View File

@@ -121,14 +121,16 @@ static void otx2_get_strings(struct net_device *netdev, u32 sset, u8 *data)
otx2_get_qset_strings(pfvf, &data, 0);
for (stats = 0; stats < CGX_RX_STATS_COUNT; stats++) {
sprintf(data, "cgx_rxstat%d: ", stats);
data += ETH_GSTRING_LEN;
}
if (!test_bit(CN10K_RPM, &pfvf->hw.cap_flag)) {
for (stats = 0; stats < CGX_RX_STATS_COUNT; stats++) {
sprintf(data, "cgx_rxstat%d: ", stats);
data += ETH_GSTRING_LEN;
}
for (stats = 0; stats < CGX_TX_STATS_COUNT; stats++) {
sprintf(data, "cgx_txstat%d: ", stats);
data += ETH_GSTRING_LEN;
for (stats = 0; stats < CGX_TX_STATS_COUNT; stats++) {
sprintf(data, "cgx_txstat%d: ", stats);
data += ETH_GSTRING_LEN;
}
}
strcpy(data, "reset_count");
@@ -205,11 +207,15 @@ static void otx2_get_ethtool_stats(struct net_device *netdev,
[otx2_drv_stats[stat].index]);
otx2_get_qset_stats(pfvf, stats, &data);
otx2_update_lmac_stats(pfvf);
for (stat = 0; stat < CGX_RX_STATS_COUNT; stat++)
*(data++) = pfvf->hw.cgx_rx_stats[stat];
for (stat = 0; stat < CGX_TX_STATS_COUNT; stat++)
*(data++) = pfvf->hw.cgx_tx_stats[stat];
if (!test_bit(CN10K_RPM, &pfvf->hw.cap_flag)) {
otx2_update_lmac_stats(pfvf);
for (stat = 0; stat < CGX_RX_STATS_COUNT; stat++)
*(data++) = pfvf->hw.cgx_rx_stats[stat];
for (stat = 0; stat < CGX_TX_STATS_COUNT; stat++)
*(data++) = pfvf->hw.cgx_tx_stats[stat];
}
*(data++) = pfvf->reset_count;
fec_corr_blks = pfvf->hw.cgx_fec_corr_blks;
@@ -242,18 +248,19 @@ static void otx2_get_ethtool_stats(struct net_device *netdev,
static int otx2_get_sset_count(struct net_device *netdev, int sset)
{
struct otx2_nic *pfvf = netdev_priv(netdev);
int qstats_count;
int qstats_count, mac_stats = 0;
if (sset != ETH_SS_STATS)
return -EINVAL;
qstats_count = otx2_n_queue_stats *
(pfvf->hw.rx_queues + pfvf->hw.tx_queues);
if (!test_bit(CN10K_RPM, &pfvf->hw.cap_flag))
mac_stats = CGX_RX_STATS_COUNT + CGX_TX_STATS_COUNT;
otx2_update_lmac_fec_stats(pfvf);
return otx2_n_dev_stats + otx2_n_drv_stats + qstats_count +
CGX_RX_STATS_COUNT + CGX_TX_STATS_COUNT + OTX2_FEC_STATS_CNT
+ 1;
mac_stats + OTX2_FEC_STATS_CNT + 1;
}
/* Get no of queues device supports and current queue count */

View File

@@ -71,7 +71,6 @@ config RPMSG_WWAN_CTRL
config IOSM
tristate "IOSM Driver for Intel M.2 WWAN Device"
depends on INTEL_IOMMU
select NET_DEVLINK
help
This driver enables Intel M.2 WWAN Device communication.

View File

@@ -18,9 +18,6 @@ iosm-y = \
iosm_ipc_protocol.o \
iosm_ipc_protocol_ops.o \
iosm_ipc_mux.o \
iosm_ipc_mux_codec.o \
iosm_ipc_devlink.o \
iosm_ipc_flash.o \
iosm_ipc_coredump.o
iosm_ipc_mux_codec.o
obj-$(CONFIG_IOSM) := iosm.o

View File

@@ -8,7 +8,7 @@
#include "iosm_ipc_chnl_cfg.h"
/* Max. sizes of a downlink buffers */
#define IPC_MEM_MAX_DL_FLASH_BUF_SIZE (64 * 1024)
#define IPC_MEM_MAX_DL_FLASH_BUF_SIZE (16 * 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)
@@ -60,10 +60,6 @@ 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)

View File

@@ -23,7 +23,6 @@ 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,
};
/**

View File

@@ -1,110 +0,0 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2020-2021 Intel Corporation.
*/
#include "iosm_ipc_coredump.h"
/* Collect coredump data from modem */
int ipc_coredump_collect(struct iosm_devlink *devlink, u8 **data, int entry,
u32 region_size)
{
int ret, bytes_to_read, bytes_read = 0, i = 0;
s32 remaining;
u8 *data_ptr;
data_ptr = vmalloc(region_size);
if (!data_ptr)
return -ENOMEM;
remaining = devlink->cd_file_info[entry].actual_size;
ret = ipc_devlink_send_cmd(devlink, rpsi_cmd_coredump_get, entry);
if (ret) {
dev_err(devlink->dev, "Send coredump_get cmd failed");
goto get_cd_fail;
}
while (remaining > 0) {
bytes_to_read = min(remaining, MAX_DATA_SIZE);
bytes_read = 0;
ret = ipc_imem_sys_devlink_read(devlink, data_ptr + i,
bytes_to_read, &bytes_read);
if (ret) {
dev_err(devlink->dev, "CD data read failed");
goto get_cd_fail;
}
remaining -= bytes_read;
i += bytes_read;
}
*data = data_ptr;
return ret;
get_cd_fail:
vfree(data_ptr);
return ret;
}
/* Get coredump list to be collected from modem */
int ipc_coredump_get_list(struct iosm_devlink *devlink, u16 cmd)
{
u32 byte_read, num_entries, file_size;
struct iosm_cd_table *cd_table;
u8 size[MAX_SIZE_LEN], i;
char *filename;
int ret = 0;
cd_table = kzalloc(MAX_CD_LIST_SIZE, GFP_KERNEL);
if (!cd_table) {
ret = -ENOMEM;
goto cd_init_fail;
}
ret = ipc_devlink_send_cmd(devlink, cmd, MAX_CD_LIST_SIZE);
if (ret) {
dev_err(devlink->dev, "rpsi_cmd_coredump_start failed");
goto cd_init_fail;
}
ret = ipc_imem_sys_devlink_read(devlink, (u8 *)cd_table,
MAX_CD_LIST_SIZE, &byte_read);
if (ret) {
dev_err(devlink->dev, "Coredump data is invalid");
goto cd_init_fail;
}
if (byte_read != MAX_CD_LIST_SIZE)
goto cd_init_fail;
if (cmd == rpsi_cmd_coredump_start) {
num_entries = le32_to_cpu(cd_table->list.num_entries);
if (num_entries == 0 || num_entries > IOSM_NOF_CD_REGION) {
ret = -EINVAL;
goto cd_init_fail;
}
for (i = 0; i < num_entries; i++) {
file_size = le32_to_cpu(cd_table->list.entry[i].size);
filename = cd_table->list.entry[i].filename;
if (file_size > devlink->cd_file_info[i].default_size) {
ret = -EINVAL;
goto cd_init_fail;
}
devlink->cd_file_info[i].actual_size = file_size;
dev_dbg(devlink->dev, "file: %s actual size %d",
filename, file_size);
devlink_flash_update_status_notify(devlink->devlink_ctx,
filename,
"FILENAME", 0, 0);
snprintf(size, sizeof(size), "%d", file_size);
devlink_flash_update_status_notify(devlink->devlink_ctx,
size, "FILE SIZE",
0, 0);
}
}
cd_init_fail:
kfree(cd_table);
return ret;
}

View File

@@ -1,75 +0,0 @@
/* SPDX-License-Identifier: GPL-2.0-only
*
* Copyright (C) 2020-2021 Intel Corporation.
*/
#ifndef _IOSM_IPC_COREDUMP_H_
#define _IOSM_IPC_COREDUMP_H_
#include "iosm_ipc_devlink.h"
/* Max number of bytes to receive for Coredump list structure */
#define MAX_CD_LIST_SIZE 0x1000
/* Max buffer allocated to receive coredump data */
#define MAX_DATA_SIZE 0x00010000
/* Max number of file entries */
#define MAX_NOF_ENTRY 256
/* Max length */
#define MAX_SIZE_LEN 32
/**
* struct iosm_cd_list_entry - Structure to hold coredump file info.
* @size: Number of bytes for the entry
* @filename: Coredump filename to be generated on host
*/
struct iosm_cd_list_entry {
__le32 size;
char filename[IOSM_MAX_FILENAME_LEN];
} __packed;
/**
* struct iosm_cd_list - Structure to hold list of coredump files
* to be collected.
* @num_entries: Number of entries to be received
* @entry: Contains File info
*/
struct iosm_cd_list {
__le32 num_entries;
struct iosm_cd_list_entry entry[MAX_NOF_ENTRY];
} __packed;
/**
* struct iosm_cd_table - Common Coredump table
* @version: Version of coredump structure
* @list: Coredump list structure
*/
struct iosm_cd_table {
__le32 version;
struct iosm_cd_list list;
} __packed;
/**
* ipc_coredump_collect - To collect coredump
* @devlink: Pointer to devlink instance.
* @data: Pointer to snapshot
* @entry: ID of requested snapshot
* @region_size: Region size
*
* Returns: 0 on success, error on failure
*/
int ipc_coredump_collect(struct iosm_devlink *devlink, u8 **data, int entry,
u32 region_size);
/**
* ipc_coredump_get_list - Get coredump list
* @devlink: Pointer to devlink instance.
* @cmd: RPSI command to be sent
*
* Returns: 0 on success, error on failure
*/
int ipc_coredump_get_list(struct iosm_devlink *devlink, u16 cmd);
#endif /* _IOSM_IPC_COREDUMP_H_ */

View File

@@ -1,360 +0,0 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2020-2021 Intel Corporation.
*/
#include "iosm_ipc_chnl_cfg.h"
#include "iosm_ipc_coredump.h"
#include "iosm_ipc_devlink.h"
#include "iosm_ipc_flash.h"
/* Coredump list */
static struct iosm_coredump_file_info list[IOSM_NOF_CD_REGION] = {
{"report.json", REPORT_JSON_SIZE,},
{"coredump.fcd", COREDUMP_FCD_SIZE,},
{"cdd.log", CDD_LOG_SIZE,},
{"eeprom.bin", EEPROM_BIN_SIZE,},
{"bootcore_trace.bin", BOOTCORE_TRC_BIN_SIZE,},
{"bootcore_prev_trace.bin", BOOTCORE_PREV_TRC_BIN_SIZE,},
};
/* Get the param values for the specific param ID's */
static int ipc_devlink_get_param(struct devlink *dl, u32 id,
struct devlink_param_gset_ctx *ctx)
{
struct iosm_devlink *ipc_devlink = devlink_priv(dl);
int rc = 0;
switch (id) {
case IOSM_DEVLINK_PARAM_ID_ERASE_FULL_FLASH:
ctx->val.vu8 = ipc_devlink->param.erase_full_flash;
break;
case IOSM_DEVLINK_PARAM_ID_DOWNLOAD_REGION:
ctx->val.vu8 = ipc_devlink->param.download_region;
break;
case IOSM_DEVLINK_PARAM_ID_ADDRESS:
ctx->val.vu32 = ipc_devlink->param.address;
break;
case IOSM_DEVLINK_PARAM_ID_REGION_COUNT:
ctx->val.vu8 = ipc_devlink->param.region_count;
break;
default:
rc = -EOPNOTSUPP;
break;
}
return rc;
}
/* Set the param values for the specific param ID's */
static int ipc_devlink_set_param(struct devlink *dl, u32 id,
struct devlink_param_gset_ctx *ctx)
{
struct iosm_devlink *ipc_devlink = devlink_priv(dl);
int rc = 0;
switch (id) {
case IOSM_DEVLINK_PARAM_ID_ERASE_FULL_FLASH:
ipc_devlink->param.erase_full_flash = ctx->val.vu8;
break;
case IOSM_DEVLINK_PARAM_ID_DOWNLOAD_REGION:
ipc_devlink->param.download_region = ctx->val.vu8;
break;
case IOSM_DEVLINK_PARAM_ID_ADDRESS:
ipc_devlink->param.address = ctx->val.vu32;
break;
case IOSM_DEVLINK_PARAM_ID_REGION_COUNT:
ipc_devlink->param.region_count = ctx->val.vu8;
break;
default:
rc = -EOPNOTSUPP;
break;
}
return rc;
}
/* Devlink param structure array */
static const struct devlink_param iosm_devlink_params[] = {
DEVLINK_PARAM_DRIVER(IOSM_DEVLINK_PARAM_ID_ERASE_FULL_FLASH,
"erase_full_flash", DEVLINK_PARAM_TYPE_BOOL,
BIT(DEVLINK_PARAM_CMODE_RUNTIME),
ipc_devlink_get_param, ipc_devlink_set_param,
NULL),
DEVLINK_PARAM_DRIVER(IOSM_DEVLINK_PARAM_ID_DOWNLOAD_REGION,
"download_region", DEVLINK_PARAM_TYPE_BOOL,
BIT(DEVLINK_PARAM_CMODE_RUNTIME),
ipc_devlink_get_param, ipc_devlink_set_param,
NULL),
DEVLINK_PARAM_DRIVER(IOSM_DEVLINK_PARAM_ID_ADDRESS,
"address", DEVLINK_PARAM_TYPE_U32,
BIT(DEVLINK_PARAM_CMODE_RUNTIME),
ipc_devlink_get_param, ipc_devlink_set_param,
NULL),
DEVLINK_PARAM_DRIVER(IOSM_DEVLINK_PARAM_ID_REGION_COUNT,
"region_count", DEVLINK_PARAM_TYPE_U8,
BIT(DEVLINK_PARAM_CMODE_RUNTIME),
ipc_devlink_get_param, ipc_devlink_set_param,
NULL),
};
/* Get devlink flash component type */
static enum iosm_flash_comp_type
ipc_devlink_get_flash_comp_type(const char comp_str[], u32 len)
{
enum iosm_flash_comp_type fls_type;
if (!strncmp("PSI", comp_str, len))
fls_type = FLASH_COMP_TYPE_PSI;
else if (!strncmp("EBL", comp_str, len))
fls_type = FLASH_COMP_TYPE_EBL;
else if (!strncmp("FLS", comp_str, len))
fls_type = FLASH_COMP_TYPE_FLS;
else
fls_type = FLASH_COMP_TYPE_INVAL;
return fls_type;
}
/* Function triggered on devlink flash command
* Flash update function which calls multiple functions based on
* component type specified in the flash command
*/
static int ipc_devlink_flash_update(struct devlink *devlink,
struct devlink_flash_update_params *params,
struct netlink_ext_ack *extack)
{
struct iosm_devlink *ipc_devlink = devlink_priv(devlink);
enum iosm_flash_comp_type fls_type;
u32 rc = -EINVAL;
u8 *mdm_rsp;
mdm_rsp = kzalloc(IOSM_EBL_DW_PACK_SIZE, GFP_KERNEL);
if (!mdm_rsp)
return -ENOMEM;
fls_type = ipc_devlink_get_flash_comp_type(params->component,
strlen(params->component));
switch (fls_type) {
case FLASH_COMP_TYPE_PSI:
rc = ipc_flash_boot_psi(ipc_devlink, params->fw);
break;
case FLASH_COMP_TYPE_EBL:
rc = ipc_flash_boot_ebl(ipc_devlink, params->fw);
if (!rc)
rc = ipc_flash_boot_set_capabilities(ipc_devlink,
mdm_rsp);
if (!rc)
rc = ipc_flash_read_swid(ipc_devlink, mdm_rsp);
break;
case FLASH_COMP_TYPE_FLS:
rc = ipc_flash_send_fls(ipc_devlink, params->fw, mdm_rsp);
break;
default:
devlink_flash_update_status_notify(devlink, "Invalid component",
params->component, 0, 0);
break;
}
if (!rc)
devlink_flash_update_status_notify(devlink, "Flashing success",
params->component, 0, 0);
else
devlink_flash_update_status_notify(devlink, "Flashing failed",
params->component, 0, 0);
kfree(mdm_rsp);
return rc;
}
/* Call back function for devlink ops */
static const struct devlink_ops devlink_flash_ops = {
.supported_flash_update_params = DEVLINK_SUPPORT_FLASH_UPDATE_COMPONENT,
.flash_update = ipc_devlink_flash_update,
};
/* Send command to modem to collect data */
int ipc_devlink_send_cmd(struct iosm_devlink *ipc_devlink, u16 cmd, u32 entry)
{
struct iosm_rpsi_cmd rpsi_cmd;
rpsi_cmd.param.dword = cpu_to_le32(entry);
rpsi_cmd.cmd = cpu_to_le16(cmd);
rpsi_cmd.crc = rpsi_cmd.param.word[0] ^ rpsi_cmd.param.word[1] ^
rpsi_cmd.cmd;
return ipc_imem_sys_devlink_write(ipc_devlink, (u8 *)&rpsi_cmd,
sizeof(rpsi_cmd));
}
static int ipc_devlink_coredump_snapshot(struct devlink *dl,
const struct devlink_region_ops *ops,
struct netlink_ext_ack *extack,
u8 **data)
{
struct iosm_devlink *ipc_devlink = devlink_priv(dl);
struct iosm_coredump_file_info *cd_list = ops->priv;
u32 region_size;
int rc;
dev_dbg(ipc_devlink->dev, "Region:%s, ID:%d", ops->name,
cd_list->entry);
region_size = cd_list->default_size;
rc = ipc_coredump_collect(ipc_devlink, data, cd_list->entry,
region_size);
if (rc) {
dev_err(ipc_devlink->dev, "Fail to create snapshot,err %d", rc);
goto coredump_collect_err;
}
/* Send coredump end cmd indicating end of coredump collection */
if (cd_list->entry == (IOSM_NOF_CD_REGION - 1))
ipc_coredump_get_list(ipc_devlink, rpsi_cmd_coredump_end);
return rc;
coredump_collect_err:
ipc_coredump_get_list(ipc_devlink, rpsi_cmd_coredump_end);
return rc;
}
/* To create regions for coredump files */
static int ipc_devlink_create_region(struct iosm_devlink *devlink)
{
struct devlink_region_ops *mdm_coredump;
int rc = 0;
u8 i;
mdm_coredump = devlink->iosm_devlink_mdm_coredump;
for (i = 0; i < IOSM_NOF_CD_REGION; i++) {
mdm_coredump[i].name = list[i].filename;
mdm_coredump[i].snapshot = ipc_devlink_coredump_snapshot;
mdm_coredump[i].destructor = vfree;
devlink->cd_regions[i] =
devlink_region_create(devlink->devlink_ctx,
&mdm_coredump[i], MAX_SNAPSHOTS,
list[i].default_size);
if (IS_ERR(devlink->cd_regions[i])) {
rc = PTR_ERR(devlink->cd_regions[i]);
dev_err(devlink->dev, "Devlink region fail,err %d", rc);
/* Delete previously created regions */
for ( ; i > 0; i--)
devlink_region_destroy(devlink->cd_regions[i]);
goto region_create_fail;
}
list[i].entry = i;
mdm_coredump[i].priv = list + i;
}
region_create_fail:
return rc;
}
/* To Destroy devlink regions */
static void ipc_devlink_destroy_region(struct iosm_devlink *ipc_devlink)
{
u8 i;
for (i = 0; i < IOSM_NOF_CD_REGION; i++)
devlink_region_destroy(ipc_devlink->cd_regions[i]);
}
/* Handle registration to devlink framework */
struct iosm_devlink *ipc_devlink_init(struct iosm_imem *ipc_imem)
{
struct ipc_chnl_cfg chnl_cfg_flash = { 0 };
struct iosm_devlink *ipc_devlink;
struct devlink *devlink_ctx;
int rc;
devlink_ctx = devlink_alloc(&devlink_flash_ops,
sizeof(struct iosm_devlink),
ipc_imem->dev);
if (!devlink_ctx) {
dev_err(ipc_imem->dev, "devlink_alloc failed");
goto devlink_alloc_fail;
}
ipc_devlink = devlink_priv(devlink_ctx);
ipc_devlink->devlink_ctx = devlink_ctx;
ipc_devlink->pcie = ipc_imem->pcie;
ipc_devlink->dev = ipc_imem->dev;
rc = devlink_register(devlink_ctx);
if (rc) {
dev_err(ipc_devlink->dev, "devlink_register failed rc %d", rc);
goto free_dl;
}
rc = devlink_params_register(devlink_ctx, iosm_devlink_params,
ARRAY_SIZE(iosm_devlink_params));
if (rc) {
dev_err(ipc_devlink->dev,
"devlink_params_register failed. rc %d", rc);
goto param_reg_fail;
}
devlink_params_publish(devlink_ctx);
ipc_devlink->cd_file_info = list;
rc = ipc_devlink_create_region(ipc_devlink);
if (rc) {
dev_err(ipc_devlink->dev, "Devlink Region create failed, rc %d",
rc);
goto region_create_fail;
}
if (ipc_chnl_cfg_get(&chnl_cfg_flash, IPC_MEM_CTRL_CHL_ID_7) < 0)
goto chnl_get_fail;
ipc_imem_channel_init(ipc_imem, IPC_CTYPE_CTRL,
chnl_cfg_flash, IRQ_MOD_OFF);
init_completion(&ipc_devlink->devlink_sio.read_sem);
skb_queue_head_init(&ipc_devlink->devlink_sio.rx_list);
dev_dbg(ipc_devlink->dev, "iosm devlink register success");
return ipc_devlink;
chnl_get_fail:
ipc_devlink_destroy_region(ipc_devlink);
region_create_fail:
devlink_params_unpublish(devlink_ctx);
devlink_params_unregister(devlink_ctx, iosm_devlink_params,
ARRAY_SIZE(iosm_devlink_params));
param_reg_fail:
devlink_unregister(devlink_ctx);
free_dl:
devlink_free(devlink_ctx);
devlink_alloc_fail:
return NULL;
}
/* Handle unregistration of devlink */
void ipc_devlink_deinit(struct iosm_devlink *ipc_devlink)
{
struct devlink *devlink_ctx = ipc_devlink->devlink_ctx;
ipc_devlink_destroy_region(ipc_devlink);
devlink_params_unpublish(devlink_ctx);
devlink_params_unregister(devlink_ctx, iosm_devlink_params,
ARRAY_SIZE(iosm_devlink_params));
if (ipc_devlink->devlink_sio.devlink_read_pend) {
complete(&ipc_devlink->devlink_sio.read_sem);
complete(&ipc_devlink->devlink_sio.channel->ul_sem);
}
if (!ipc_devlink->devlink_sio.devlink_read_pend)
skb_queue_purge(&ipc_devlink->devlink_sio.rx_list);
ipc_imem_sys_devlink_close(ipc_devlink);
devlink_unregister(devlink_ctx);
devlink_free(devlink_ctx);
}

View File

@@ -1,207 +0,0 @@
/* SPDX-License-Identifier: GPL-2.0-only
*
* Copyright (C) 2020-2021 Intel Corporation.
*/
#ifndef _IOSM_IPC_DEVLINK_H_
#define _IOSM_IPC_DEVLINK_H_
#include <net/devlink.h>
#include "iosm_ipc_imem.h"
#include "iosm_ipc_imem_ops.h"
#include "iosm_ipc_pcie.h"
/* MAX file name length */
#define IOSM_MAX_FILENAME_LEN 32
/* EBL response size */
#define IOSM_EBL_RSP_SIZE 76
/* MAX number of regions supported */
#define IOSM_NOF_CD_REGION 6
/* MAX number of SNAPSHOTS supported */
#define MAX_SNAPSHOTS 1
/* Default Coredump file size */
#define REPORT_JSON_SIZE 0x800
#define COREDUMP_FCD_SIZE 0x10E00000
#define CDD_LOG_SIZE 0x30000
#define EEPROM_BIN_SIZE 0x10000
#define BOOTCORE_TRC_BIN_SIZE 0x8000
#define BOOTCORE_PREV_TRC_BIN_SIZE 0x20000
/**
* enum iosm_devlink_param_id - Enum type to different devlink params
* @IOSM_DEVLINK_PARAM_ID_BASE: Devlink param base ID
* @IOSM_DEVLINK_PARAM_ID_ERASE_FULL_FLASH: Set if full erase required
* @IOSM_DEVLINK_PARAM_ID_DOWNLOAD_REGION: Set if fls file to be
* flashed is Loadmap/region file
* @IOSM_DEVLINK_PARAM_ID_ADDRESS: Address of the region to be
* flashed
* @IOSM_DEVLINK_PARAM_ID_REGION_COUNT: Max region count
*/
enum iosm_devlink_param_id {
IOSM_DEVLINK_PARAM_ID_BASE = DEVLINK_PARAM_GENERIC_ID_MAX,
IOSM_DEVLINK_PARAM_ID_ERASE_FULL_FLASH,
IOSM_DEVLINK_PARAM_ID_DOWNLOAD_REGION,
IOSM_DEVLINK_PARAM_ID_ADDRESS,
IOSM_DEVLINK_PARAM_ID_REGION_COUNT,
};
/**
* enum iosm_rpsi_cmd_code - Enum type for RPSI command list
* @rpsi_cmd_code_ebl: Command to load ebl
* @rpsi_cmd_coredump_start: Command to get list of files and
* file size info from PSI
* @rpsi_cmd_coredump_get: Command to get the coredump data
* @rpsi_cmd_coredump_end: Command to stop receiving the coredump
*/
enum iosm_rpsi_cmd_code {
rpsi_cmd_code_ebl = 0x02,
rpsi_cmd_coredump_start = 0x10,
rpsi_cmd_coredump_get = 0x11,
rpsi_cmd_coredump_end = 0x12,
};
/**
* enum iosm_flash_comp_type - Enum for different flash component types
* @FLASH_COMP_TYPE_PSI: PSI flash comp type
* @FLASH_COMP_TYPE_EBL: EBL flash comp type
* @FLASH_COMP_TYPE_FLS: FLS flash comp type
* @FLASH_COMP_TYPE_INVAL: Invalid flash comp type
*/
enum iosm_flash_comp_type {
FLASH_COMP_TYPE_PSI,
FLASH_COMP_TYPE_EBL,
FLASH_COMP_TYPE_FLS,
FLASH_COMP_TYPE_INVAL,
};
/**
* struct iosm_devlink_sio - SIO instance
* @rx_list: Downlink skbuf list received from CP
* @read_sem: Needed for the blocking read or downlink transfer
* @channel_id: Reserved channel id for flashing/CD collection to RAM
* @channel: Channel instance for flashing and coredump
* @devlink_read_pend: Check if read is pending
*/
struct iosm_devlink_sio {
struct sk_buff_head rx_list;
struct completion read_sem;
int channel_id;
struct ipc_mem_channel *channel;
u32 devlink_read_pend;
};
/**
* struct iosm_flash_params - List of flash params required for flashing
* @address: Address of the region file to be flashed
* @region_count: Maximum no of regions for each fls file
* @download_region: To be set if region is being flashed
* @erase_full_flash: To set the flashing mode
* erase_full_flash = 1; full erase
* erase_full_flash = 0; no erase
* @erase_full_flash_done: Flag to check if it is a full erase
*/
struct iosm_flash_params {
u32 address;
u8 region_count;
u8 download_region;
u8 erase_full_flash;
u8 erase_full_flash_done;
};
/**
* struct iosm_ebl_ctx_data - EBL ctx data used during flashing
* @ebl_sw_info_version: SWID version info obtained from EBL
* @m_ebl_resp: Buffer used to read and write the ebl data
*/
struct iosm_ebl_ctx_data {
u8 ebl_sw_info_version;
u8 m_ebl_resp[IOSM_EBL_RSP_SIZE];
};
/**
* struct iosm_coredump_file_info - Coredump file info
* @filename: Name of coredump file
* @default_size: Default size of coredump file
* @actual_size: Actual size of coredump file
* @entry: Index of the coredump file
*/
struct iosm_coredump_file_info {
char filename[IOSM_MAX_FILENAME_LEN];
u32 default_size;
u32 actual_size;
u32 entry;
};
/**
* struct iosm_devlink - IOSM Devlink structure
* @devlink_sio: SIO instance for read/write functionality
* @pcie: Pointer to PCIe component
* @dev: Pointer to device struct
* @devlink_ctx: Pointer to devlink context
* @param: Params required for flashing
* @ebl_ctx: Data to be read and written to Modem
* @cd_file_info: coredump file info
* @iosm_devlink_mdm_coredump: region ops for coredump collection
* @cd_regions: coredump regions
*/
struct iosm_devlink {
struct iosm_devlink_sio devlink_sio;
struct iosm_pcie *pcie;
struct device *dev;
struct devlink *devlink_ctx;
struct iosm_flash_params param;
struct iosm_ebl_ctx_data ebl_ctx;
struct iosm_coredump_file_info *cd_file_info;
struct devlink_region_ops iosm_devlink_mdm_coredump[IOSM_NOF_CD_REGION];
struct devlink_region *cd_regions[IOSM_NOF_CD_REGION];
};
/**
* union iosm_rpsi_param_u - RPSI cmd param for CRC calculation
* @word: Words member used in CRC calculation
* @dword: Actual data
*/
union iosm_rpsi_param_u {
__le16 word[2];
__le32 dword;
};
/**
* struct iosm_rpsi_cmd - Structure for RPSI Command
* @param: Used to calculate CRC
* @cmd: Stores the RPSI command
* @crc: Stores the CRC value
*/
struct iosm_rpsi_cmd {
union iosm_rpsi_param_u param;
__le16 cmd;
__le16 crc;
};
/**
* ipc_devlink_init - To initialize the devlink to IOSM driver
* @ipc_imem: Pointer to struct iosm_imem
*
* Returns: Pointer to iosm_devlink on success and NULL on failure
*/
struct iosm_devlink *ipc_devlink_init(struct iosm_imem *ipc_imem);
/**
* ipc_devlink_deinit - To unintialize the devlink from IOSM driver.
* @ipc_devlink: Devlink instance
*/
void ipc_devlink_deinit(struct iosm_devlink *ipc_devlink);
/**
* ipc_devlink_send_cmd - Send command to Modem
* @ipc_devlink: Pointer to struct iosm_devlink
* @cmd: Command to be sent to modem
* @entry: Command entry number
*
* Returns: 0 on success and failure value on error
*/
int ipc_devlink_send_cmd(struct iosm_devlink *ipc_devlink, u16 cmd, u32 entry);
#endif /* _IOSM_IPC_DEVLINK_H */

View File

@@ -1,562 +0,0 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2020-2021 Intel Corporation.
*/
#include "iosm_ipc_coredump.h"
#include "iosm_ipc_devlink.h"
#include "iosm_ipc_flash.h"
/* This function will pack the data to be sent to the modem using the
* payload, payload length and pack id
*/
static int ipc_flash_proc_format_ebl_pack(struct iosm_flash_data *flash_req,
u32 pack_length, u16 pack_id,
u8 *payload, u32 payload_length)
{
u16 checksum = pack_id;
u32 i;
if (payload_length + IOSM_EBL_HEAD_SIZE > pack_length)
return -EINVAL;
flash_req->pack_id = cpu_to_le16(pack_id);
flash_req->msg_length = cpu_to_le32(payload_length);
checksum += (payload_length >> IOSM_EBL_PAYL_SHIFT) +
(payload_length & IOSM_EBL_CKSM);
for (i = 0; i < payload_length; i++)
checksum += payload[i];
flash_req->checksum = cpu_to_le16(checksum);
return 0;
}
/* validate the response received from modem and
* check the type of errors received
*/
static int ipc_flash_proc_check_ebl_rsp(void *hdr_rsp, void *payload_rsp)
{
struct iosm_ebl_error *err_info = payload_rsp;
u16 *rsp_code = hdr_rsp;
int res = 0;
u32 i;
if (*rsp_code == IOSM_EBL_RSP_BUFF) {
for (i = 0; i < IOSM_MAX_ERRORS; i++) {
if (!err_info->error[i].error_code) {
pr_err("EBL: error_class = %d, error_code = %d",
err_info->error[i].error_class,
err_info->error[i].error_code);
}
}
res = -EINVAL;
}
return res;
}
/* Send data to the modem */
static int ipc_flash_send_data(struct iosm_devlink *ipc_devlink, u32 size,
u16 pack_id, u8 *payload, u32 payload_length)
{
struct iosm_flash_data flash_req;
int ret;
ret = ipc_flash_proc_format_ebl_pack(&flash_req, size,
pack_id, payload, payload_length);
if (ret) {
dev_err(ipc_devlink->dev, "EBL2 pack failed for pack_id:%d",
pack_id);
goto ipc_free_payload;
}
ret = ipc_imem_sys_devlink_write(ipc_devlink, (u8 *)&flash_req,
IOSM_EBL_HEAD_SIZE);
if (ret) {
dev_err(ipc_devlink->dev, "EBL Header write failed for Id:%x",
pack_id);
goto ipc_free_payload;
}
ret = ipc_imem_sys_devlink_write(ipc_devlink, payload, payload_length);
if (ret) {
dev_err(ipc_devlink->dev, "EBL Payload write failed for Id:%x",
pack_id);
}
ipc_free_payload:
return ret;
}
/* Allocate flash channel and read LER data from modem */
int ipc_flash_link_establish(struct iosm_imem *ipc_imem)
{
u8 ler_data[IOSM_LER_RSP_SIZE];
u32 bytes_read;
/* Allocate channel for flashing/cd collection */
ipc_imem->ipc_devlink->devlink_sio.channel =
ipc_imem_sys_devlink_open(ipc_imem);
if (!ipc_imem->ipc_devlink->devlink_sio.channel)
goto chl_open_fail;
if (ipc_imem_sys_devlink_read(ipc_imem->ipc_devlink, ler_data,
IOSM_LER_RSP_SIZE, &bytes_read))
goto devlink_read_fail;
if (bytes_read != IOSM_LER_RSP_SIZE)
goto devlink_read_fail;
return 0;
devlink_read_fail:
ipc_imem_sys_devlink_close(ipc_imem->ipc_devlink);
chl_open_fail:
return -EIO;
}
/* Receive data from the modem */
static int ipc_flash_receive_data(struct iosm_devlink *ipc_devlink, u32 size,
u8 *mdm_rsp)
{
u8 mdm_rsp_hdr[IOSM_EBL_HEAD_SIZE];
u32 bytes_read;
int ret;
ret = ipc_imem_sys_devlink_read(ipc_devlink, mdm_rsp_hdr,
IOSM_EBL_HEAD_SIZE, &bytes_read);
if (ret) {
dev_err(ipc_devlink->dev, "EBL rsp to read %d bytes failed",
IOSM_EBL_HEAD_SIZE);
goto ipc_flash_recv_err;
}
if (bytes_read != IOSM_EBL_HEAD_SIZE) {
ret = -EINVAL;
goto ipc_flash_recv_err;
}
ret = ipc_imem_sys_devlink_read(ipc_devlink, mdm_rsp, size,
&bytes_read);
if (ret) {
dev_err(ipc_devlink->dev, "EBL rsp to read %d bytes failed",
size);
goto ipc_flash_recv_err;
}
if (bytes_read != size) {
ret = -EINVAL;
goto ipc_flash_recv_err;
}
ret = ipc_flash_proc_check_ebl_rsp(mdm_rsp_hdr + 2, mdm_rsp);
ipc_flash_recv_err:
return ret;
}
/* Function to send command to modem and receive response */
static int ipc_flash_send_receive(struct iosm_devlink *ipc_devlink, u16 pack_id,
u8 *payload, u32 payload_length, u8 *mdm_rsp)
{
size_t frame_len = IOSM_EBL_DW_PACK_SIZE;
int ret;
if (pack_id == FLASH_SET_PROT_CONF)
frame_len = IOSM_EBL_W_PACK_SIZE;
ret = ipc_flash_send_data(ipc_devlink, frame_len, pack_id, payload,
payload_length);
if (ret)
goto ipc_flash_send_rcv;
ret = ipc_flash_receive_data(ipc_devlink,
frame_len - IOSM_EBL_HEAD_SIZE, mdm_rsp);
ipc_flash_send_rcv:
return ret;
}
/* Set the capabilities for the EBL */
int ipc_flash_boot_set_capabilities(struct iosm_devlink *ipc_devlink,
u8 *mdm_rsp)
{
int ret;
ipc_devlink->ebl_ctx.ebl_sw_info_version =
ipc_devlink->ebl_ctx.m_ebl_resp[EBL_RSP_SW_INFO_VER];
ipc_devlink->ebl_ctx.m_ebl_resp[EBL_SKIP_ERASE] = IOSM_CAP_NOT_ENHANCED;
ipc_devlink->ebl_ctx.m_ebl_resp[EBL_SKIP_CRC] = IOSM_CAP_NOT_ENHANCED;
if (ipc_devlink->ebl_ctx.m_ebl_resp[EBL_CAPS_FLAG] &
IOSM_CAP_USE_EXT_CAP) {
if (ipc_devlink->param.erase_full_flash)
ipc_devlink->ebl_ctx.m_ebl_resp[EBL_OOS_CONFIG] &=
~((u8)IOSM_EXT_CAP_ERASE_ALL);
else
ipc_devlink->ebl_ctx.m_ebl_resp[EBL_OOS_CONFIG] &=
~((u8)IOSM_EXT_CAP_COMMIT_ALL);
ipc_devlink->ebl_ctx.m_ebl_resp[EBL_EXT_CAPS_HANDLED] =
IOSM_CAP_USE_EXT_CAP;
}
/* Write back the EBL capability to modem
* Request Set Protcnf command
*/
ret = ipc_flash_send_receive(ipc_devlink, FLASH_SET_PROT_CONF,
ipc_devlink->ebl_ctx.m_ebl_resp,
IOSM_EBL_RSP_SIZE, mdm_rsp);
return ret;
}
/* Read the SWID type and SWID value from the EBL */
int ipc_flash_read_swid(struct iosm_devlink *ipc_devlink, u8 *mdm_rsp)
{
struct iosm_flash_msg_control cmd_msg;
struct iosm_swid_table *swid;
char ebl_swid[IOSM_SWID_STR];
int ret;
if (ipc_devlink->ebl_ctx.ebl_sw_info_version !=
IOSM_EXT_CAP_SWID_OOS_PACK)
return -EINVAL;
cmd_msg.action = cpu_to_le32(FLASH_OOSC_ACTION_READ);
cmd_msg.type = cpu_to_le32(FLASH_OOSC_TYPE_SWID_TABLE);
cmd_msg.length = cpu_to_le32(IOSM_MSG_LEN_ARG);
cmd_msg.arguments = cpu_to_le32(IOSM_MSG_LEN_ARG);
ret = ipc_flash_send_receive(ipc_devlink, FLASH_OOS_CONTROL,
(u8 *)&cmd_msg, IOSM_MDM_SEND_16, mdm_rsp);
if (ret)
goto ipc_swid_err;
cmd_msg.action = cpu_to_le32(*((u32 *)mdm_rsp));
ret = ipc_flash_send_receive(ipc_devlink, FLASH_OOS_DATA_READ,
(u8 *)&cmd_msg, IOSM_MDM_SEND_4, mdm_rsp);
if (ret)
goto ipc_swid_err;
swid = (struct iosm_swid_table *)mdm_rsp;
dev_dbg(ipc_devlink->dev, "SWID %x RF_ENGINE_ID %x", swid->sw_id_val,
swid->rf_engine_id_val);
snprintf(ebl_swid, sizeof(ebl_swid), "SWID: %x, RF_ENGINE_ID: %x",
swid->sw_id_val, swid->rf_engine_id_val);
devlink_flash_update_status_notify(ipc_devlink->devlink_ctx, ebl_swid,
NULL, 0, 0);
ipc_swid_err:
return ret;
}
/* Function to check if full erase or conditional erase was successful */
static int ipc_flash_erase_check(struct iosm_devlink *ipc_devlink, u8 *mdm_rsp)
{
int ret, count = 0;
u16 mdm_rsp_data;
/* Request Flash Erase Check */
do {
mdm_rsp_data = IOSM_MDM_SEND_DATA;
ret = ipc_flash_send_receive(ipc_devlink, FLASH_ERASE_CHECK,
(u8 *)&mdm_rsp_data,
IOSM_MDM_SEND_2, mdm_rsp);
if (ret)
goto ipc_erase_chk_err;
mdm_rsp_data = *((u16 *)mdm_rsp);
if (mdm_rsp_data > IOSM_MDM_ERASE_RSP) {
dev_err(ipc_devlink->dev,
"Flash Erase Check resp wrong 0x%04X",
mdm_rsp_data);
ret = -EINVAL;
goto ipc_erase_chk_err;
}
count++;
msleep(IOSM_FLASH_ERASE_CHECK_INTERVAL);
} while ((mdm_rsp_data != IOSM_MDM_ERASE_RSP) &&
(count < (IOSM_FLASH_ERASE_CHECK_TIMEOUT /
IOSM_FLASH_ERASE_CHECK_INTERVAL)));
if (mdm_rsp_data != IOSM_MDM_ERASE_RSP) {
dev_err(ipc_devlink->dev, "Modem erase check timeout failure!");
ret = -ETIMEDOUT;
}
ipc_erase_chk_err:
return ret;
}
/* Full erase function which will erase the nand flash through EBL command */
static int ipc_flash_full_erase(struct iosm_devlink *ipc_devlink, u8 *mdm_rsp)
{
u32 erase_address = IOSM_ERASE_START_ADDR;
struct iosm_flash_msg_control cmd_msg;
u32 erase_length = IOSM_ERASE_LEN;
int ret;
dev_dbg(ipc_devlink->dev, "Erase full nand flash");
cmd_msg.action = cpu_to_le32(FLASH_OOSC_ACTION_ERASE);
cmd_msg.type = cpu_to_le32(FLASH_OOSC_TYPE_ALL_FLASH);
cmd_msg.length = cpu_to_le32(erase_length);
cmd_msg.arguments = cpu_to_le32(erase_address);
ret = ipc_flash_send_receive(ipc_devlink, FLASH_OOS_CONTROL,
(unsigned char *)&cmd_msg,
IOSM_MDM_SEND_16, mdm_rsp);
if (ret)
goto ipc_flash_erase_err;
ipc_devlink->param.erase_full_flash_done = IOSM_SET_FLAG;
ret = ipc_flash_erase_check(ipc_devlink, mdm_rsp);
ipc_flash_erase_err:
return ret;
}
/* Logic for flashing all the Loadmaps available for individual fls file */
static int ipc_flash_download_region(struct iosm_devlink *ipc_devlink,
const struct firmware *fw, u8 *mdm_rsp)
{
__le32 reg_info[2]; /* 0th position region address, 1st position size */
char *file_ptr;
u32 rest_len;
u32 raw_len;
int ret;
file_ptr = (char *)fw->data;
reg_info[0] = cpu_to_le32(ipc_devlink->param.address);
if (!ipc_devlink->param.erase_full_flash_done) {
reg_info[1] = cpu_to_le32(ipc_devlink->param.address +
fw->size - 2);
ret = ipc_flash_send_receive(ipc_devlink, FLASH_ERASE_START,
(u8 *)reg_info, IOSM_MDM_SEND_8,
mdm_rsp);
if (ret)
goto dl_region_fail;
ret = ipc_flash_erase_check(ipc_devlink, mdm_rsp);
if (ret)
goto dl_region_fail;
}
/* Request Flash Set Address */
ret = ipc_flash_send_receive(ipc_devlink, FLASH_SET_ADDRESS,
(u8 *)reg_info, IOSM_MDM_SEND_4, mdm_rsp);
if (ret)
goto dl_region_fail;
rest_len = fw->size;
/* Request Flash Write Raw Image */
ret = ipc_flash_send_data(ipc_devlink, IOSM_EBL_DW_PACK_SIZE,
FLASH_WRITE_IMAGE_RAW, (u8 *)&rest_len,
IOSM_MDM_SEND_4);
if (ret)
goto dl_region_fail;
do {
raw_len = (rest_len > IOSM_FLS_BUF_SIZE) ? IOSM_FLS_BUF_SIZE :
rest_len;
ret = ipc_imem_sys_devlink_write(ipc_devlink, file_ptr,
raw_len);
if (ret) {
dev_err(ipc_devlink->dev, "Image write failed");
goto dl_region_fail;
}
file_ptr += raw_len;
rest_len -= raw_len;
} while (rest_len);
ret = ipc_flash_receive_data(ipc_devlink, IOSM_EBL_DW_PAYL_SIZE,
mdm_rsp);
dl_region_fail:
return ret;
}
/* Flash the individual fls files */
int ipc_flash_send_fls(struct iosm_devlink *ipc_devlink,
const struct firmware *fw, u8 *mdm_rsp)
{
u16 flash_cmd;
int ret;
if (ipc_devlink->param.erase_full_flash) {
ipc_devlink->param.erase_full_flash = false;
ret = ipc_flash_full_erase(ipc_devlink, mdm_rsp);
if (ret)
goto ipc_flash_err;
}
/* Request Sec Start */
if (!ipc_devlink->param.download_region) {
ret = ipc_flash_send_receive(ipc_devlink, FLASH_SEC_START,
(u8 *)fw->data, fw->size, mdm_rsp);
if (ret)
goto ipc_flash_err;
} else {
/* Download regions */
ipc_devlink->param.region_count -= IOSM_SET_FLAG;
ret = ipc_flash_download_region(ipc_devlink, fw, mdm_rsp);
if (ret)
goto ipc_flash_err;
if (!ipc_devlink->param.region_count) {
/* Request Sec End */
flash_cmd = IOSM_MDM_SEND_DATA;
ret = ipc_flash_send_receive(ipc_devlink, FLASH_SEC_END,
(u8 *)&flash_cmd,
IOSM_MDM_SEND_2, mdm_rsp);
}
}
ipc_flash_err:
return ret;
}
/* Inject RPSI */
int ipc_flash_boot_psi(struct iosm_devlink *ipc_devlink,
const struct firmware *fw)
{
u8 psi_ack_byte[IOSM_PSI_ACK], read_data[2];
u32 bytes_read;
u8 *psi_code;
int ret;
dev_dbg(ipc_devlink->dev, "Boot transfer PSI");
psi_code = kzalloc(fw->size, GFP_KERNEL);
if (!psi_code)
return -ENOMEM;
memcpy(psi_code, fw->data, fw->size);
ret = ipc_imem_sys_devlink_write(ipc_devlink, psi_code, fw->size);
if (ret) {
dev_err(ipc_devlink->dev, "RPSI Image write failed");
goto ipc_flash_psi_free;
}
ret = ipc_imem_sys_devlink_read(ipc_devlink, read_data,
IOSM_LER_ACK_SIZE, &bytes_read);
if (ret) {
dev_err(ipc_devlink->dev, "ipc_devlink_sio_read ACK failed");
goto ipc_flash_psi_free;
}
if (bytes_read != IOSM_LER_ACK_SIZE) {
ret = -EINVAL;
goto ipc_flash_psi_free;
}
snprintf(psi_ack_byte, sizeof(psi_ack_byte), "%x%x", read_data[0],
read_data[1]);
devlink_flash_update_status_notify(ipc_devlink->devlink_ctx,
psi_ack_byte, "PSI ACK", 0, 0);
if (read_data[0] == 0x00 && read_data[1] == 0xCD) {
dev_dbg(ipc_devlink->dev, "Coredump detected");
ret = ipc_coredump_get_list(ipc_devlink,
rpsi_cmd_coredump_start);
if (ret)
dev_err(ipc_devlink->dev, "Failed to get cd list");
}
ipc_flash_psi_free:
kfree(psi_code);
return ret;
}
/* Inject EBL */
int ipc_flash_boot_ebl(struct iosm_devlink *ipc_devlink,
const struct firmware *fw)
{
u32 ebl_size = fw->size;
u8 read_data[2];
u32 bytes_read;
int ret;
if (ipc_mmio_get_exec_stage(ipc_devlink->pcie->imem->mmio) !=
IPC_MEM_EXEC_STAGE_PSI) {
devlink_flash_update_status_notify(ipc_devlink->devlink_ctx,
"Invalid execution stage",
NULL, 0, 0);
return -EINVAL;
}
dev_dbg(ipc_devlink->dev, "Boot transfer EBL");
ret = ipc_devlink_send_cmd(ipc_devlink, rpsi_cmd_code_ebl,
IOSM_RPSI_LOAD_SIZE);
if (ret) {
dev_err(ipc_devlink->dev, "Sending rpsi_cmd_code_ebl failed");
goto ipc_flash_ebl_err;
}
ret = ipc_imem_sys_devlink_read(ipc_devlink, read_data, IOSM_READ_SIZE,
&bytes_read);
if (ret) {
dev_err(ipc_devlink->dev, "rpsi_cmd_code_ebl read failed");
goto ipc_flash_ebl_err;
}
if (bytes_read != IOSM_READ_SIZE) {
ret = -EINVAL;
goto ipc_flash_ebl_err;
}
ret = ipc_imem_sys_devlink_write(ipc_devlink, (u8 *)&ebl_size,
sizeof(ebl_size));
if (ret) {
dev_err(ipc_devlink->dev, "EBL length write failed");
goto ipc_flash_ebl_err;
}
ret = ipc_imem_sys_devlink_read(ipc_devlink, read_data, IOSM_READ_SIZE,
&bytes_read);
if (ret) {
dev_err(ipc_devlink->dev, "EBL read failed");
goto ipc_flash_ebl_err;
}
if (bytes_read != IOSM_READ_SIZE) {
ret = -EINVAL;
goto ipc_flash_ebl_err;
}
ret = ipc_imem_sys_devlink_write(ipc_devlink, (unsigned char *)fw->data,
fw->size);
if (ret) {
dev_err(ipc_devlink->dev, "EBL data transfer failed");
goto ipc_flash_ebl_err;
}
ret = ipc_imem_sys_devlink_read(ipc_devlink, read_data, IOSM_READ_SIZE,
&bytes_read);
if (ret) {
dev_err(ipc_devlink->dev, "EBL read failed");
goto ipc_flash_ebl_err;
}
if (bytes_read != IOSM_READ_SIZE) {
ret = -EINVAL;
goto ipc_flash_ebl_err;
}
ret = ipc_imem_sys_devlink_read(ipc_devlink,
ipc_devlink->ebl_ctx.m_ebl_resp,
IOSM_EBL_RSP_SIZE, &bytes_read);
if (ret) {
dev_err(ipc_devlink->dev, "EBL response read failed");
goto ipc_flash_ebl_err;
}
if (bytes_read != IOSM_EBL_RSP_SIZE)
ret = -EINVAL;
ipc_flash_ebl_err:
return ret;
}

View File

@@ -1,271 +0,0 @@
/* SPDX-License-Identifier: GPL-2.0-only
*
* Copyright (C) 2020-2021 Intel Corporation.
*/
#ifndef _IOSM_IPC_FLASH_H
#define _IOSM_IPC_FLASH_H
/* Buffer size used to read the fls image */
#define IOSM_FLS_BUF_SIZE 0x00100000
/* Full erase start address */
#define IOSM_ERASE_START_ADDR 0x00000000
/* Erase length for NAND flash */
#define IOSM_ERASE_LEN 0xFFFFFFFF
/* EBL response Header size */
#define IOSM_EBL_HEAD_SIZE 8
/* EBL payload size */
#define IOSM_EBL_W_PAYL_SIZE 2048
/* Total EBL pack size */
#define IOSM_EBL_W_PACK_SIZE (IOSM_EBL_HEAD_SIZE + IOSM_EBL_W_PAYL_SIZE)
/* EBL payload size */
#define IOSM_EBL_DW_PAYL_SIZE 16384
/* Total EBL pack size */
#define IOSM_EBL_DW_PACK_SIZE (IOSM_EBL_HEAD_SIZE + IOSM_EBL_DW_PAYL_SIZE)
/* EBL name size */
#define IOSM_EBL_NAME 32
/* Maximum supported error types */
#define IOSM_MAX_ERRORS 8
/* Read size for RPSI/EBL response */
#define IOSM_READ_SIZE 2
/* Link establishment response ack size */
#define IOSM_LER_ACK_SIZE 2
/* PSI ACK len */
#define IOSM_PSI_ACK 8
/* SWID capability for packed swid type */
#define IOSM_EXT_CAP_SWID_OOS_PACK 0x02
/* EBL error response buffer */
#define IOSM_EBL_RSP_BUFF 0x0041
/* SWID string length */
#define IOSM_SWID_STR 64
/* Load EBL command size */
#define IOSM_RPSI_LOAD_SIZE 0
/* EBL payload checksum */
#define IOSM_EBL_CKSM 0x0000FFFF
/* SWID msg len and argument */
#define IOSM_MSG_LEN_ARG 0
/* Data to be sent to modem */
#define IOSM_MDM_SEND_DATA 0x0000
/* Data received from modem as part of erase check */
#define IOSM_MDM_ERASE_RSP 0x0001
/* Bit shift to calculate Checksum */
#define IOSM_EBL_PAYL_SHIFT 16
/* Flag To be set */
#define IOSM_SET_FLAG 1
/* Set flash erase check timeout to 100 msec */
#define IOSM_FLASH_ERASE_CHECK_TIMEOUT 100
/* Set flash erase check interval to 20 msec */
#define IOSM_FLASH_ERASE_CHECK_INTERVAL 20
/* Link establishment response ack size */
#define IOSM_LER_RSP_SIZE 60
/**
* enum iosm_flash_package_type - Enum for the flashing operations
* @FLASH_SET_PROT_CONF: Write EBL capabilities
* @FLASH_SEC_START: Start writing the secpack
* @FLASH_SEC_END: Validate secpack end
* @FLASH_SET_ADDRESS: Set the address for flashing
* @FLASH_ERASE_START: Start erase before flashing
* @FLASH_ERASE_CHECK: Validate the erase functionality
* @FLASH_OOS_CONTROL: Retrieve data based on oos actions
* @FLASH_OOS_DATA_READ: Read data from EBL
* @FLASH_WRITE_IMAGE_RAW: Write the raw image to flash
*/
enum iosm_flash_package_type {
FLASH_SET_PROT_CONF = 0x0086,
FLASH_SEC_START = 0x0204,
FLASH_SEC_END,
FLASH_SET_ADDRESS = 0x0802,
FLASH_ERASE_START = 0x0805,
FLASH_ERASE_CHECK,
FLASH_OOS_CONTROL = 0x080C,
FLASH_OOS_DATA_READ = 0x080E,
FLASH_WRITE_IMAGE_RAW,
};
/**
* enum iosm_out_of_session_action - Actions possible over the
* OutOfSession command interface
* @FLASH_OOSC_ACTION_READ: Read data according to its type
* @FLASH_OOSC_ACTION_ERASE: Erase data according to its type
*/
enum iosm_out_of_session_action {
FLASH_OOSC_ACTION_READ = 2,
FLASH_OOSC_ACTION_ERASE = 3,
};
/**
* enum iosm_out_of_session_type - Data types that can be handled over the
* Out Of Session command Interface
* @FLASH_OOSC_TYPE_ALL_FLASH: The whole flash area
* @FLASH_OOSC_TYPE_SWID_TABLE: Read the swid table from the target
*/
enum iosm_out_of_session_type {
FLASH_OOSC_TYPE_ALL_FLASH = 8,
FLASH_OOSC_TYPE_SWID_TABLE = 16,
};
/**
* enum iosm_ebl_caps - EBL capability settings
* @IOSM_CAP_NOT_ENHANCED: If capability not supported
* @IOSM_CAP_USE_EXT_CAP: To be set if extended capability is set
* @IOSM_EXT_CAP_ERASE_ALL: Set Erase all capability
* @IOSM_EXT_CAP_COMMIT_ALL: Set the commit all capability
*/
enum iosm_ebl_caps {
IOSM_CAP_NOT_ENHANCED = 0x00,
IOSM_CAP_USE_EXT_CAP = 0x01,
IOSM_EXT_CAP_ERASE_ALL = 0x08,
IOSM_EXT_CAP_COMMIT_ALL = 0x20,
};
/**
* enum iosm_ebl_rsp - EBL response field
* @EBL_CAPS_FLAG: EBL capability flag
* @EBL_SKIP_ERASE: EBL skip erase flag
* @EBL_SKIP_CRC: EBL skip wr_pack crc
* @EBL_EXT_CAPS_HANDLED: EBL extended capability handled flag
* @EBL_OOS_CONFIG: EBL oos configuration
* @EBL_RSP_SW_INFO_VER: EBL SW info version
*/
enum iosm_ebl_rsp {
EBL_CAPS_FLAG = 50,
EBL_SKIP_ERASE = 54,
EBL_SKIP_CRC = 55,
EBL_EXT_CAPS_HANDLED = 57,
EBL_OOS_CONFIG = 64,
EBL_RSP_SW_INFO_VER = 70,
};
/**
* enum iosm_mdm_send_recv_data - Data to send to modem
* @IOSM_MDM_SEND_2: Send 2 bytes of payload
* @IOSM_MDM_SEND_4: Send 4 bytes of payload
* @IOSM_MDM_SEND_8: Send 8 bytes of payload
* @IOSM_MDM_SEND_16: Send 16 bytes of payload
*/
enum iosm_mdm_send_recv_data {
IOSM_MDM_SEND_2 = 2,
IOSM_MDM_SEND_4 = 4,
IOSM_MDM_SEND_8 = 8,
IOSM_MDM_SEND_16 = 16,
};
/**
* struct iosm_ebl_one_error - Structure containing error details
* @error_class: Error type- standard, security and text error
* @error_code: Specific error from error type
*/
struct iosm_ebl_one_error {
u16 error_class;
u16 error_code;
};
/**
* struct iosm_ebl_error- Structure with max error type supported
* @error: Array of one_error structure with max errors
*/
struct iosm_ebl_error {
struct iosm_ebl_one_error error[IOSM_MAX_ERRORS];
};
/**
* struct iosm_swid_table - SWID table data for modem
* @number_of_data_sets: Number of swid types
* @sw_id_type: SWID type - SWID
* @sw_id_val: SWID value
* @rf_engine_id_type: RF engine ID type - RF_ENGINE_ID
* @rf_engine_id_val: RF engine ID value
*/
struct iosm_swid_table {
u32 number_of_data_sets;
char sw_id_type[IOSM_EBL_NAME];
u32 sw_id_val;
char rf_engine_id_type[IOSM_EBL_NAME];
u32 rf_engine_id_val;
};
/**
* struct iosm_flash_msg_control - Data sent to modem
* @action: Action to be performed
* @type: Type of action
* @length: Length of the action
* @arguments: Argument value sent to modem
*/
struct iosm_flash_msg_control {
__le32 action;
__le32 type;
__le32 length;
__le32 arguments;
};
/**
* struct iosm_flash_data - Header Data to be sent to modem
* @checksum: Checksum value calculated for the payload data
* @pack_id: Flash Action type
* @msg_length: Payload length
*/
struct iosm_flash_data {
__le16 checksum;
__le16 pack_id;
__le32 msg_length;
};
/**
* ipc_flash_boot_psi - Inject PSI image
* @ipc_devlink: Pointer to devlink structure
* @fw: FW image
*
* Returns: 0 on success and failure value on error
*/
int ipc_flash_boot_psi(struct iosm_devlink *ipc_devlink,
const struct firmware *fw);
/**
* ipc_flash_boot_ebl - Inject EBL image
* @ipc_devlink: Pointer to devlink structure
* @fw: FW image
*
* Returns: 0 on success and failure value on error
*/
int ipc_flash_boot_ebl(struct iosm_devlink *ipc_devlink,
const struct firmware *fw);
/**
* ipc_flash_boot_set_capabilities - Set modem bool capabilities in flash
* @ipc_devlink: Pointer to devlink structure
* @mdm_rsp: Pointer to modem response buffer
*
* Returns: 0 on success and failure value on error
*/
int ipc_flash_boot_set_capabilities(struct iosm_devlink *ipc_devlink,
u8 *mdm_rsp);
/**
* ipc_flash_link_establish - Flash link establishment
* @ipc_imem: Pointer to struct iosm_imem
*
* Returns: 0 on success and failure value on error
*/
int ipc_flash_link_establish(struct iosm_imem *ipc_imem);
/**
* ipc_flash_read_swid - Get swid during flash phase
* @ipc_devlink: Pointer to devlink structure
* @mdm_rsp: Pointer to modem response buffer
*
* Returns: 0 on success and failure value on error
*/
int ipc_flash_read_swid(struct iosm_devlink *ipc_devlink, u8 *mdm_rsp);
/**
* ipc_flash_send_fls - Inject Modem subsystem fls file to device
* @ipc_devlink: Pointer to devlink structure
* @fw: FW image
* @mdm_rsp: Pointer to modem response buffer
*
* Returns: 0 on success and failure value on error
*/
int ipc_flash_send_fls(struct iosm_devlink *ipc_devlink,
const struct firmware *fw, u8 *mdm_rsp);
#endif

View File

@@ -6,8 +6,6 @@
#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"
@@ -265,12 +263,9 @@ 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;
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);
/* Pass the packet to the wwan layer. */
wwan_port_rx(ipc_imem->ipc_port[port_id]->iosm_port, skb);
break;
case IPC_CTYPE_WWAN:
@@ -404,8 +399,19 @@ static void ipc_imem_rom_irq_exec(struct iosm_imem *ipc_imem)
{
struct ipc_mem_channel *channel;
channel = ipc_imem->ipc_devlink->devlink_sio.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;
}
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);
}
@@ -566,7 +572,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 i;
int ch_id, i;
if (irq != IMEM_IRQ_DONT_CARE)
ipc_imem->ev_irq_pending[irq] = false;
@@ -690,8 +696,11 @@ 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) {
complete(&ipc_imem->ipc_devlink->devlink_sio.channel->ul_sem);
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);
}
/* Reset the expected CP state. */
@@ -1167,9 +1176,6 @@ 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);
@@ -1252,7 +1258,6 @@ 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;
@@ -1267,6 +1272,9 @@ 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;
@@ -1320,21 +1328,8 @@ struct iosm_imem *ipc_imem_init(struct iosm_pcie *pcie, unsigned int device_id,
goto imem_config_fail;
}
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);
@@ -1366,51 +1361,3 @@ 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);
}

View File

@@ -69,7 +69,7 @@ struct ipc_chnl_cfg;
#define IMEM_IRQ_DONT_CARE (-1)
#define IPC_MEM_MAX_CHANNELS 8
#define IPC_MEM_MAX_CHANNELS 7
#define IPC_MEM_MUX_IP_SESSION_ENTRIES 8
@@ -98,7 +98,6 @@ 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
@@ -305,9 +304,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.
@@ -350,9 +349,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;
@@ -576,15 +575,4 @@ 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

View File

@@ -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;
}

View File

@@ -9,7 +9,7 @@
#include "iosm_ipc_mux_codec.h"
/* Maximum wait time for blocking read */
#define IPC_READ_TIMEOUT 3000
#define IPC_READ_TIMEOUT 500
/* The delay in ms for defering the unregister */
#define SIO_UNREGISTER_DEFER_DELAY_MS 1
@@ -98,51 +98,4 @@ int ipc_imem_sys_wwan_transmit(struct iosm_imem *ipc_imem, int if_id,
*/
void ipc_imem_wwan_channel_init(struct iosm_imem *ipc_imem,
enum ipc_mux_protocol mux_type);
/**
* ipc_imem_sys_devlink_open - Open a Flash/CD Channel link to CP
* @ipc_imem: iosm_imem instance
*
* Return: channel instance on success, NULL for failure
*/
struct ipc_mem_channel *ipc_imem_sys_devlink_open(struct iosm_imem *ipc_imem);
/**
* ipc_imem_sys_devlink_close - Release a Flash/CD channel link to CP
* @ipc_devlink: Pointer to ipc_devlink data-struct
*
*/
void ipc_imem_sys_devlink_close(struct iosm_devlink *ipc_devlink);
/**
* ipc_imem_sys_devlink_notify_rx - Receive downlink characters from CP,
* the downlink skbuf is added at the end of the
* downlink or rx list
* @ipc_devlink: Pointer to ipc_devlink data-struct
* @skb: Pointer to sk buffer
*/
void ipc_imem_sys_devlink_notify_rx(struct iosm_devlink *ipc_devlink,
struct sk_buff *skb);
/**
* ipc_imem_sys_devlink_read - Copy the rx data and free the skbuf
* @ipc_devlink: Devlink instance
* @data: Buffer to read the data from modem
* @bytes_to_read: Size of destination buffer
* @bytes_read: Number of bytes read
*
* Return: 0 on success and failure value on error
*/
int ipc_imem_sys_devlink_read(struct iosm_devlink *ipc_devlink, u8 *data,
u32 bytes_to_read, u32 *bytes_read);
/**
* ipc_imem_sys_devlink_write - Route the uplink buffer to CP
* @ipc_devlink: Devlink_sio instance
* @buf: Pointer to buffer
* @count: Number of data bytes to write
* Return: 0 on success and failure value on error
*/
int ipc_imem_sys_devlink_write(struct iosm_devlink *ipc_devlink,
unsigned char *buf, int count);
#endif

View File

@@ -84,6 +84,20 @@
#define TLS_CIPHER_CHACHA20_POLY1305_TAG_SIZE 16
#define TLS_CIPHER_CHACHA20_POLY1305_REC_SEQ_SIZE 8
#define TLS_CIPHER_SM4_GCM 55
#define TLS_CIPHER_SM4_GCM_IV_SIZE 8
#define TLS_CIPHER_SM4_GCM_KEY_SIZE 16
#define TLS_CIPHER_SM4_GCM_SALT_SIZE 4
#define TLS_CIPHER_SM4_GCM_TAG_SIZE 16
#define TLS_CIPHER_SM4_GCM_REC_SEQ_SIZE 8
#define TLS_CIPHER_SM4_CCM 56
#define TLS_CIPHER_SM4_CCM_IV_SIZE 8
#define TLS_CIPHER_SM4_CCM_KEY_SIZE 16
#define TLS_CIPHER_SM4_CCM_SALT_SIZE 4
#define TLS_CIPHER_SM4_CCM_TAG_SIZE 16
#define TLS_CIPHER_SM4_CCM_REC_SEQ_SIZE 8
#define TLS_SET_RECORD_TYPE 1
#define TLS_GET_RECORD_TYPE 2
@@ -124,6 +138,22 @@ struct tls12_crypto_info_chacha20_poly1305 {
unsigned char rec_seq[TLS_CIPHER_CHACHA20_POLY1305_REC_SEQ_SIZE];
};
struct tls12_crypto_info_sm4_gcm {
struct tls_crypto_info info;
unsigned char iv[TLS_CIPHER_SM4_GCM_IV_SIZE];
unsigned char key[TLS_CIPHER_SM4_GCM_KEY_SIZE];
unsigned char salt[TLS_CIPHER_SM4_GCM_SALT_SIZE];
unsigned char rec_seq[TLS_CIPHER_SM4_GCM_REC_SEQ_SIZE];
};
struct tls12_crypto_info_sm4_ccm {
struct tls_crypto_info info;
unsigned char iv[TLS_CIPHER_SM4_CCM_IV_SIZE];
unsigned char key[TLS_CIPHER_SM4_CCM_KEY_SIZE];
unsigned char salt[TLS_CIPHER_SM4_CCM_SALT_SIZE];
unsigned char rec_seq[TLS_CIPHER_SM4_CCM_REC_SEQ_SIZE];
};
enum {
TLS_INFO_UNSPEC,
TLS_INFO_VERSION,

View File

@@ -421,6 +421,46 @@ static int do_tls_getsockopt_conf(struct sock *sk, char __user *optval,
rc = -EFAULT;
break;
}
case TLS_CIPHER_SM4_GCM: {
struct tls12_crypto_info_sm4_gcm *sm4_gcm_info =
container_of(crypto_info,
struct tls12_crypto_info_sm4_gcm, info);
if (len != sizeof(*sm4_gcm_info)) {
rc = -EINVAL;
goto out;
}
lock_sock(sk);
memcpy(sm4_gcm_info->iv,
cctx->iv + TLS_CIPHER_SM4_GCM_SALT_SIZE,
TLS_CIPHER_SM4_GCM_IV_SIZE);
memcpy(sm4_gcm_info->rec_seq, cctx->rec_seq,
TLS_CIPHER_SM4_GCM_REC_SEQ_SIZE);
release_sock(sk);
if (copy_to_user(optval, sm4_gcm_info, sizeof(*sm4_gcm_info)))
rc = -EFAULT;
break;
}
case TLS_CIPHER_SM4_CCM: {
struct tls12_crypto_info_sm4_ccm *sm4_ccm_info =
container_of(crypto_info,
struct tls12_crypto_info_sm4_ccm, info);
if (len != sizeof(*sm4_ccm_info)) {
rc = -EINVAL;
goto out;
}
lock_sock(sk);
memcpy(sm4_ccm_info->iv,
cctx->iv + TLS_CIPHER_SM4_CCM_SALT_SIZE,
TLS_CIPHER_SM4_CCM_IV_SIZE);
memcpy(sm4_ccm_info->rec_seq, cctx->rec_seq,
TLS_CIPHER_SM4_CCM_REC_SEQ_SIZE);
release_sock(sk);
if (copy_to_user(optval, sm4_ccm_info, sizeof(*sm4_ccm_info)))
rc = -EFAULT;
break;
}
default:
rc = -EINVAL;
}
@@ -524,6 +564,12 @@ static int do_tls_setsockopt_conf(struct sock *sk, sockptr_t optval,
case TLS_CIPHER_CHACHA20_POLY1305:
optsize = sizeof(struct tls12_crypto_info_chacha20_poly1305);
break;
case TLS_CIPHER_SM4_GCM:
optsize = sizeof(struct tls12_crypto_info_sm4_gcm);
break;
case TLS_CIPHER_SM4_CCM:
optsize = sizeof(struct tls12_crypto_info_sm4_ccm);
break;
default:
rc = -EINVAL;
goto err_crypto_info;

View File

@@ -2433,6 +2433,40 @@ int tls_set_sw_offload(struct sock *sk, struct tls_context *ctx, int tx)
cipher_name = "rfc7539(chacha20,poly1305)";
break;
}
case TLS_CIPHER_SM4_GCM: {
struct tls12_crypto_info_sm4_gcm *sm4_gcm_info;
sm4_gcm_info = (void *)crypto_info;
nonce_size = TLS_CIPHER_SM4_GCM_IV_SIZE;
tag_size = TLS_CIPHER_SM4_GCM_TAG_SIZE;
iv_size = TLS_CIPHER_SM4_GCM_IV_SIZE;
iv = sm4_gcm_info->iv;
rec_seq_size = TLS_CIPHER_SM4_GCM_REC_SEQ_SIZE;
rec_seq = sm4_gcm_info->rec_seq;
keysize = TLS_CIPHER_SM4_GCM_KEY_SIZE;
key = sm4_gcm_info->key;
salt = sm4_gcm_info->salt;
salt_size = TLS_CIPHER_SM4_GCM_SALT_SIZE;
cipher_name = "gcm(sm4)";
break;
}
case TLS_CIPHER_SM4_CCM: {
struct tls12_crypto_info_sm4_ccm *sm4_ccm_info;
sm4_ccm_info = (void *)crypto_info;
nonce_size = TLS_CIPHER_SM4_CCM_IV_SIZE;
tag_size = TLS_CIPHER_SM4_CCM_TAG_SIZE;
iv_size = TLS_CIPHER_SM4_CCM_IV_SIZE;
iv = sm4_ccm_info->iv;
rec_seq_size = TLS_CIPHER_SM4_CCM_REC_SEQ_SIZE;
rec_seq = sm4_ccm_info->rec_seq;
keysize = TLS_CIPHER_SM4_CCM_KEY_SIZE;
key = sm4_ccm_info->key;
salt = sm4_ccm_info->salt;
salt_size = TLS_CIPHER_SM4_CCM_SALT_SIZE;
cipher_name = "ccm(sm4)";
break;
}
default:
rc = -EINVAL;
goto free_priv;