18c2ecf20Sopenharmony_ci/********************************************************************** 28c2ecf20Sopenharmony_ci * Author: Cavium, Inc. 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * Contact: support@cavium.com 58c2ecf20Sopenharmony_ci * Please include "LiquidIO" in the subject. 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Copyright (c) 2003-2016 Cavium, Inc. 88c2ecf20Sopenharmony_ci * 98c2ecf20Sopenharmony_ci * This file is free software; you can redistribute it and/or modify 108c2ecf20Sopenharmony_ci * it under the terms of the GNU General Public License, Version 2, as 118c2ecf20Sopenharmony_ci * published by the Free Software Foundation. 128c2ecf20Sopenharmony_ci * 138c2ecf20Sopenharmony_ci * This file is distributed in the hope that it will be useful, but 148c2ecf20Sopenharmony_ci * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty 158c2ecf20Sopenharmony_ci * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or 168c2ecf20Sopenharmony_ci * NONINFRINGEMENT. See the GNU General Public License for more 178c2ecf20Sopenharmony_ci * details. 188c2ecf20Sopenharmony_ci **********************************************************************/ 198c2ecf20Sopenharmony_ci#include <linux/pci.h> 208c2ecf20Sopenharmony_ci#include <linux/netdevice.h> 218c2ecf20Sopenharmony_ci#include "liquidio_common.h" 228c2ecf20Sopenharmony_ci#include "octeon_droq.h" 238c2ecf20Sopenharmony_ci#include "octeon_iq.h" 248c2ecf20Sopenharmony_ci#include "response_manager.h" 258c2ecf20Sopenharmony_ci#include "octeon_device.h" 268c2ecf20Sopenharmony_ci#include "octeon_nic.h" 278c2ecf20Sopenharmony_ci#include "octeon_main.h" 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_civoid * 308c2ecf20Sopenharmony_ciocteon_alloc_soft_command_resp(struct octeon_device *oct, 318c2ecf20Sopenharmony_ci union octeon_instr_64B *cmd, 328c2ecf20Sopenharmony_ci u32 rdatasize) 338c2ecf20Sopenharmony_ci{ 348c2ecf20Sopenharmony_ci struct octeon_soft_command *sc; 358c2ecf20Sopenharmony_ci struct octeon_instr_ih3 *ih3; 368c2ecf20Sopenharmony_ci struct octeon_instr_ih2 *ih2; 378c2ecf20Sopenharmony_ci struct octeon_instr_irh *irh; 388c2ecf20Sopenharmony_ci struct octeon_instr_rdp *rdp; 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_ci sc = (struct octeon_soft_command *) 418c2ecf20Sopenharmony_ci octeon_alloc_soft_command(oct, 0, rdatasize, 0); 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_ci if (!sc) 448c2ecf20Sopenharmony_ci return NULL; 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_ci /* Copy existing command structure into the soft command */ 478c2ecf20Sopenharmony_ci memcpy(&sc->cmd, cmd, sizeof(union octeon_instr_64B)); 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci /* Add in the response related fields. Opcode and Param are already 508c2ecf20Sopenharmony_ci * there. 518c2ecf20Sopenharmony_ci */ 528c2ecf20Sopenharmony_ci if (OCTEON_CN23XX_PF(oct) || OCTEON_CN23XX_VF(oct)) { 538c2ecf20Sopenharmony_ci ih3 = (struct octeon_instr_ih3 *)&sc->cmd.cmd3.ih3; 548c2ecf20Sopenharmony_ci rdp = (struct octeon_instr_rdp *)&sc->cmd.cmd3.rdp; 558c2ecf20Sopenharmony_ci irh = (struct octeon_instr_irh *)&sc->cmd.cmd3.irh; 568c2ecf20Sopenharmony_ci /*pkiih3 + irh + ossp[0] + ossp[1] + rdp + rptr = 40 bytes */ 578c2ecf20Sopenharmony_ci ih3->fsz = LIO_SOFTCMDRESP_IH3; 588c2ecf20Sopenharmony_ci } else { 598c2ecf20Sopenharmony_ci ih2 = (struct octeon_instr_ih2 *)&sc->cmd.cmd2.ih2; 608c2ecf20Sopenharmony_ci rdp = (struct octeon_instr_rdp *)&sc->cmd.cmd2.rdp; 618c2ecf20Sopenharmony_ci irh = (struct octeon_instr_irh *)&sc->cmd.cmd2.irh; 628c2ecf20Sopenharmony_ci /* irh + ossp[0] + ossp[1] + rdp + rptr = 40 bytes */ 638c2ecf20Sopenharmony_ci ih2->fsz = LIO_SOFTCMDRESP_IH2; 648c2ecf20Sopenharmony_ci } 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_ci irh->rflag = 1; /* a response is required */ 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_ci rdp->pcie_port = oct->pcie_port; 698c2ecf20Sopenharmony_ci rdp->rlen = rdatasize; 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_ci *sc->status_word = COMPLETION_WORD_INIT; 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ci if (OCTEON_CN23XX_PF(oct) || OCTEON_CN23XX_VF(oct)) 748c2ecf20Sopenharmony_ci sc->cmd.cmd3.rptr = sc->dmarptr; 758c2ecf20Sopenharmony_ci else 768c2ecf20Sopenharmony_ci sc->cmd.cmd2.rptr = sc->dmarptr; 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_ci sc->expiry_time = jiffies + msecs_to_jiffies(LIO_SC_MAX_TMO_MS); 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_ci return sc; 818c2ecf20Sopenharmony_ci} 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_ciint octnet_send_nic_data_pkt(struct octeon_device *oct, 848c2ecf20Sopenharmony_ci struct octnic_data_pkt *ndata, 858c2ecf20Sopenharmony_ci int xmit_more) 868c2ecf20Sopenharmony_ci{ 878c2ecf20Sopenharmony_ci int ring_doorbell = !xmit_more; 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_ci return octeon_send_command(oct, ndata->q_no, ring_doorbell, &ndata->cmd, 908c2ecf20Sopenharmony_ci ndata->buf, ndata->datasize, 918c2ecf20Sopenharmony_ci ndata->reqtype); 928c2ecf20Sopenharmony_ci} 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_cistatic inline struct octeon_soft_command 958c2ecf20Sopenharmony_ci*octnic_alloc_ctrl_pkt_sc(struct octeon_device *oct, 968c2ecf20Sopenharmony_ci struct octnic_ctrl_pkt *nctrl) 978c2ecf20Sopenharmony_ci{ 988c2ecf20Sopenharmony_ci struct octeon_soft_command *sc = NULL; 998c2ecf20Sopenharmony_ci u8 *data; 1008c2ecf20Sopenharmony_ci u32 rdatasize; 1018c2ecf20Sopenharmony_ci u32 uddsize = 0, datasize = 0; 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_ci uddsize = (u32)(nctrl->ncmd.s.more * 8); 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_ci datasize = OCTNET_CMD_SIZE + uddsize; 1068c2ecf20Sopenharmony_ci rdatasize = 16; 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_ci sc = (struct octeon_soft_command *) 1098c2ecf20Sopenharmony_ci octeon_alloc_soft_command(oct, datasize, rdatasize, 0); 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ci if (!sc) 1128c2ecf20Sopenharmony_ci return NULL; 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ci data = (u8 *)sc->virtdptr; 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_ci memcpy(data, &nctrl->ncmd, OCTNET_CMD_SIZE); 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_ci octeon_swap_8B_data((u64 *)data, (OCTNET_CMD_SIZE >> 3)); 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_ci if (uddsize) { 1218c2ecf20Sopenharmony_ci /* Endian-Swap for UDD should have been done by caller. */ 1228c2ecf20Sopenharmony_ci memcpy(data + OCTNET_CMD_SIZE, nctrl->udd, uddsize); 1238c2ecf20Sopenharmony_ci } 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_ci sc->iq_no = (u32)nctrl->iq_no; 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_ci octeon_prepare_soft_command(oct, sc, OPCODE_NIC, OPCODE_NIC_CMD, 1288c2ecf20Sopenharmony_ci 0, 0, 0); 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ci init_completion(&sc->complete); 1318c2ecf20Sopenharmony_ci sc->sc_status = OCTEON_REQUEST_PENDING; 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ci return sc; 1348c2ecf20Sopenharmony_ci} 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_ciint 1378c2ecf20Sopenharmony_cioctnet_send_nic_ctrl_pkt(struct octeon_device *oct, 1388c2ecf20Sopenharmony_ci struct octnic_ctrl_pkt *nctrl) 1398c2ecf20Sopenharmony_ci{ 1408c2ecf20Sopenharmony_ci int retval; 1418c2ecf20Sopenharmony_ci struct octeon_soft_command *sc = NULL; 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ci spin_lock_bh(&oct->cmd_resp_wqlock); 1448c2ecf20Sopenharmony_ci /* Allow only rx ctrl command to stop traffic on the chip 1458c2ecf20Sopenharmony_ci * during offline operations 1468c2ecf20Sopenharmony_ci */ 1478c2ecf20Sopenharmony_ci if ((oct->cmd_resp_state == OCT_DRV_OFFLINE) && 1488c2ecf20Sopenharmony_ci (nctrl->ncmd.s.cmd != OCTNET_CMD_RX_CTL)) { 1498c2ecf20Sopenharmony_ci spin_unlock_bh(&oct->cmd_resp_wqlock); 1508c2ecf20Sopenharmony_ci dev_err(&oct->pci_dev->dev, 1518c2ecf20Sopenharmony_ci "%s cmd:%d not processed since driver offline\n", 1528c2ecf20Sopenharmony_ci __func__, nctrl->ncmd.s.cmd); 1538c2ecf20Sopenharmony_ci return -1; 1548c2ecf20Sopenharmony_ci } 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_ci sc = octnic_alloc_ctrl_pkt_sc(oct, nctrl); 1578c2ecf20Sopenharmony_ci if (!sc) { 1588c2ecf20Sopenharmony_ci dev_err(&oct->pci_dev->dev, "%s soft command alloc failed\n", 1598c2ecf20Sopenharmony_ci __func__); 1608c2ecf20Sopenharmony_ci spin_unlock_bh(&oct->cmd_resp_wqlock); 1618c2ecf20Sopenharmony_ci return -1; 1628c2ecf20Sopenharmony_ci } 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_ci retval = octeon_send_soft_command(oct, sc); 1658c2ecf20Sopenharmony_ci if (retval == IQ_SEND_FAILED) { 1668c2ecf20Sopenharmony_ci octeon_free_soft_command(oct, sc); 1678c2ecf20Sopenharmony_ci dev_err(&oct->pci_dev->dev, "%s pf_num:%d soft command:%d send failed status: %x\n", 1688c2ecf20Sopenharmony_ci __func__, oct->pf_num, nctrl->ncmd.s.cmd, retval); 1698c2ecf20Sopenharmony_ci spin_unlock_bh(&oct->cmd_resp_wqlock); 1708c2ecf20Sopenharmony_ci return -1; 1718c2ecf20Sopenharmony_ci } 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_ci spin_unlock_bh(&oct->cmd_resp_wqlock); 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_ci if (nctrl->ncmd.s.cmdgroup == 0) { 1768c2ecf20Sopenharmony_ci switch (nctrl->ncmd.s.cmd) { 1778c2ecf20Sopenharmony_ci /* caller holds lock, can not sleep */ 1788c2ecf20Sopenharmony_ci case OCTNET_CMD_CHANGE_DEVFLAGS: 1798c2ecf20Sopenharmony_ci case OCTNET_CMD_SET_MULTI_LIST: 1808c2ecf20Sopenharmony_ci case OCTNET_CMD_SET_UC_LIST: 1818c2ecf20Sopenharmony_ci WRITE_ONCE(sc->caller_is_done, true); 1828c2ecf20Sopenharmony_ci return retval; 1838c2ecf20Sopenharmony_ci } 1848c2ecf20Sopenharmony_ci } 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_ci retval = wait_for_sc_completion_timeout(oct, sc, 0); 1878c2ecf20Sopenharmony_ci if (retval) 1888c2ecf20Sopenharmony_ci return (retval); 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_ci nctrl->sc_status = sc->sc_status; 1918c2ecf20Sopenharmony_ci retval = nctrl->sc_status; 1928c2ecf20Sopenharmony_ci if (nctrl->cb_fn) 1938c2ecf20Sopenharmony_ci nctrl->cb_fn(nctrl); 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_ci WRITE_ONCE(sc->caller_is_done, true); 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_ci return retval; 1988c2ecf20Sopenharmony_ci} 199