/** * \brief Net device change_mtu * @param netdev network device */ int liquidio_change_mtu(struct net_device *netdev, int new_mtu) { struct lio *lio = GET_LIO(netdev); struct octeon_device *oct = lio->oct_dev; struct octeon_soft_command *sc; union octnet_cmd *ncmd; int ret = 0; sc = (struct octeon_soft_command *) octeon_alloc_soft_command(oct, OCTNET_CMD_SIZE, 16, 0); ncmd = (union octnet_cmd *)sc->virtdptr; init_completion(&sc->complete); sc->sc_status = OCTEON_REQUEST_PENDING; ncmd->u64 = 0; ncmd->s.cmd = OCTNET_CMD_CHANGE_MTU; ncmd->s.param1 = new_mtu; octeon_swap_8B_data((u64 *)ncmd, (OCTNET_CMD_SIZE >> 3)); sc->iq_no = lio->linfo.txpciq[0].s.q_no; octeon_prepare_soft_command(oct, sc, OPCODE_NIC, OPCODE_NIC_CMD, 0, 0, 0); ret = octeon_send_soft_command(oct, sc); if (ret == IQ_SEND_FAILED) { netif_info(lio, rx_err, lio->netdev, "Failed to change MTU\n"); octeon_free_soft_command(oct, sc); return -EINVAL; } /* Sleep on a wait queue till the cond flag indicates that the * response arrived or timed-out. */ ret = wait_for_sc_completion_timeout(oct, sc, 0); if (ret) return ret; if (sc->sc_status) { WRITE_ONCE(sc->caller_is_done, true); return -EINVAL; } netdev->mtu = new_mtu; lio->mtu = new_mtu; WRITE_ONCE(sc->caller_is_done, true); return 0; }
/* Configure interrupt moderation parameters */ static int octnet_set_intrmod_cfg(struct lio *lio, struct oct_intrmod_cfg *intr_cfg) { struct octeon_soft_command *sc; struct oct_intrmod_cmd *cmd; struct oct_intrmod_cfg *cfg; int retval; struct octeon_device *oct_dev = lio->oct_dev; /* Alloc soft command */ sc = (struct octeon_soft_command *) octeon_alloc_soft_command(oct_dev, sizeof(struct oct_intrmod_cfg), 0, sizeof(struct oct_intrmod_cmd)); if (!sc) return -ENOMEM; cmd = (struct oct_intrmod_cmd *)sc->ctxptr; cfg = (struct oct_intrmod_cfg *)sc->virtdptr; memcpy(cfg, intr_cfg, sizeof(struct oct_intrmod_cfg)); octeon_swap_8B_data((u64 *)cfg, (sizeof(struct oct_intrmod_cfg)) / 8); cmd->sc = sc; cmd->cfg = cfg; cmd->oct_dev = oct_dev; sc->iq_no = lio->linfo.txpciq[0].s.q_no; octeon_prepare_soft_command(oct_dev, sc, OPCODE_NIC, OPCODE_NIC_INTRMOD_CFG, 0, 0, 0); sc->callback = octnet_intrmod_callback; sc->callback_arg = cmd; sc->wait_time = 1000; retval = octeon_send_soft_command(oct_dev, sc); if (retval == IQ_SEND_FAILED) { octeon_free_soft_command(oct_dev, sc); return -EINVAL; } return 0; }
static inline struct octeon_soft_command *octnic_alloc_ctrl_pkt_sc(struct octeon_device *oct, struct octnic_ctrl_pkt *nctrl) { struct octeon_soft_command *sc = NULL; u8 *data; u32 rdatasize; u32 uddsize = 0, datasize = 0; uddsize = (u32)(nctrl->ncmd.s.more * 8); datasize = OCTNET_CMD_SIZE + uddsize; rdatasize = (nctrl->wait_time) ? 16 : 0; sc = (struct octeon_soft_command *) octeon_alloc_soft_command(oct, datasize, rdatasize, sizeof(struct octnic_ctrl_pkt)); if (!sc) return NULL; memcpy(sc->ctxptr, nctrl, sizeof(struct octnic_ctrl_pkt)); data = (u8 *)sc->virtdptr; memcpy(data, &nctrl->ncmd, OCTNET_CMD_SIZE); octeon_swap_8B_data((u64 *)data, (OCTNET_CMD_SIZE >> 3)); if (uddsize) { /* Endian-Swap for UDD should have been done by caller. */ memcpy(data + OCTNET_CMD_SIZE, nctrl->udd, uddsize); } sc->iq_no = (u32)nctrl->iq_no; octeon_prepare_soft_command(oct, sc, OPCODE_NIC, OPCODE_NIC_CMD, 0, 0, 0); sc->callback = octnet_link_ctrl_callback; sc->callback_arg = sc; sc->wait_time = nctrl->wait_time; return sc; }
void * octeon_alloc_soft_command_resp(struct octeon_device *oct, union octeon_instr_64B *cmd, u32 rdatasize) { struct octeon_soft_command *sc; struct octeon_instr_ih2 *ih2; struct octeon_instr_irh *irh; struct octeon_instr_rdp *rdp; sc = (struct octeon_soft_command *) octeon_alloc_soft_command(oct, 0, rdatasize, 0); if (!sc) return NULL; /* Copy existing command structure into the soft command */ memcpy(&sc->cmd, cmd, sizeof(union octeon_instr_64B)); /* Add in the response related fields. Opcode and Param are already * there. */ ih2 = (struct octeon_instr_ih2 *)&sc->cmd.cmd2.ih2; rdp = (struct octeon_instr_rdp *)&sc->cmd.cmd2.rdp; irh = (struct octeon_instr_irh *)&sc->cmd.cmd2.irh; ih2->fsz = 40; /* irh + ossp[0] + ossp[1] + rdp + rptr = 40 bytes */ irh->rflag = 1; /* a response is required */ rdp->pcie_port = oct->pcie_port; rdp->rlen = rdatasize; *sc->status_word = COMPLETION_WORD_INIT; sc->cmd.cmd2.rptr = sc->dmarptr; sc->wait_time = 1000; sc->timeout = jiffies + sc->wait_time; return sc; }
/* This routine provides PHY access routines for * mdio clause45 . */ static int octnet_mdio45_access(struct lio *lio, int op, int loc, int *value) { struct octeon_device *oct_dev = lio->oct_dev; struct octeon_soft_command *sc; struct oct_mdio_cmd_resp *mdio_cmd_rsp; struct oct_mdio_cmd_context *mdio_cmd_ctx; struct oct_mdio_cmd *mdio_cmd; int retval = 0; sc = (struct octeon_soft_command *) octeon_alloc_soft_command(oct_dev, sizeof(struct oct_mdio_cmd), sizeof(struct oct_mdio_cmd_resp), sizeof(struct oct_mdio_cmd_context)); if (!sc) return -ENOMEM; mdio_cmd_ctx = (struct oct_mdio_cmd_context *)sc->ctxptr; mdio_cmd_rsp = (struct oct_mdio_cmd_resp *)sc->virtrptr; mdio_cmd = (struct oct_mdio_cmd *)sc->virtdptr; ACCESS_ONCE(mdio_cmd_ctx->cond) = 0; mdio_cmd_ctx->octeon_id = lio_get_device_id(oct_dev); mdio_cmd->op = op; mdio_cmd->mdio_addr = loc; if (op) mdio_cmd->value1 = *value; octeon_swap_8B_data((u64 *)mdio_cmd, sizeof(struct oct_mdio_cmd) / 8); sc->iq_no = lio->linfo.txpciq[0].s.q_no; octeon_prepare_soft_command(oct_dev, sc, OPCODE_NIC, OPCODE_NIC_MDIO45, 0, 0, 0); sc->wait_time = 1000; sc->callback = octnet_mdio_resp_callback; sc->callback_arg = sc; init_waitqueue_head(&mdio_cmd_ctx->wc); retval = octeon_send_soft_command(oct_dev, sc); if (retval == IQ_SEND_FAILED) { dev_err(&oct_dev->pci_dev->dev, "octnet_mdio45_access instruction failed status: %x\n", retval); retval = -EBUSY; } else { /* Sleep on a wait queue till the cond flag indicates that the * response arrived */ sleep_cond(&mdio_cmd_ctx->wc, &mdio_cmd_ctx->cond); retval = mdio_cmd_rsp->status; if (retval) { dev_err(&oct_dev->pci_dev->dev, "octnet mdio45 access failed\n"); retval = -EBUSY; } else { octeon_swap_8B_data((u64 *)(&mdio_cmd_rsp->resp), sizeof(struct oct_mdio_cmd) / 8); if (ACCESS_ONCE(mdio_cmd_ctx->cond) == 1) { if (!op) *value = mdio_cmd_rsp->resp.value1; } else { retval = -EINVAL; } } } octeon_free_soft_command(oct_dev, sc); return retval; }