in ethernet/cavium/liquidio/lio_main.c [3328:3781]
static int setup_nic_devices(struct octeon_device *octeon_dev)
{
struct lio *lio = NULL;
struct net_device *netdev;
u8 mac[6], i, j, *fw_ver, *micro_ver;
unsigned long micro;
u32 cur_ver;
struct octeon_soft_command *sc;
struct liquidio_if_cfg_resp *resp;
struct octdev_props *props;
int retval, num_iqueues, num_oqueues;
int max_num_queues = 0;
union oct_nic_if_cfg if_cfg;
unsigned int base_queue;
unsigned int gmx_port_id;
u32 resp_size, data_size;
u32 ifidx_or_pfnum;
struct lio_version *vdata;
struct devlink *devlink;
struct lio_devlink_priv *lio_devlink;
/* This is to handle link status changes */
octeon_register_dispatch_fn(octeon_dev, OPCODE_NIC,
OPCODE_NIC_INFO,
lio_nic_info, octeon_dev);
/* REQTYPE_RESP_NET and REQTYPE_SOFT_COMMAND do not have free functions.
* They are handled directly.
*/
octeon_register_reqtype_free_fn(octeon_dev, REQTYPE_NORESP_NET,
free_netbuf);
octeon_register_reqtype_free_fn(octeon_dev, REQTYPE_NORESP_NET_SG,
free_netsgbuf);
octeon_register_reqtype_free_fn(octeon_dev, REQTYPE_RESP_NET_SG,
free_netsgbuf_with_resp);
for (i = 0; i < octeon_dev->ifcount; i++) {
resp_size = sizeof(struct liquidio_if_cfg_resp);
data_size = sizeof(struct lio_version);
sc = (struct octeon_soft_command *)
octeon_alloc_soft_command(octeon_dev, data_size,
resp_size, 0);
resp = (struct liquidio_if_cfg_resp *)sc->virtrptr;
vdata = (struct lio_version *)sc->virtdptr;
*((u64 *)vdata) = 0;
vdata->major = cpu_to_be16(LIQUIDIO_BASE_MAJOR_VERSION);
vdata->minor = cpu_to_be16(LIQUIDIO_BASE_MINOR_VERSION);
vdata->micro = cpu_to_be16(LIQUIDIO_BASE_MICRO_VERSION);
if (OCTEON_CN23XX_PF(octeon_dev)) {
num_iqueues = octeon_dev->sriov_info.num_pf_rings;
num_oqueues = octeon_dev->sriov_info.num_pf_rings;
base_queue = octeon_dev->sriov_info.pf_srn;
gmx_port_id = octeon_dev->pf_num;
ifidx_or_pfnum = octeon_dev->pf_num;
} else {
num_iqueues = CFG_GET_NUM_TXQS_NIC_IF(
octeon_get_conf(octeon_dev), i);
num_oqueues = CFG_GET_NUM_RXQS_NIC_IF(
octeon_get_conf(octeon_dev), i);
base_queue = CFG_GET_BASE_QUE_NIC_IF(
octeon_get_conf(octeon_dev), i);
gmx_port_id = CFG_GET_GMXID_NIC_IF(
octeon_get_conf(octeon_dev), i);
ifidx_or_pfnum = i;
}
dev_dbg(&octeon_dev->pci_dev->dev,
"requesting config for interface %d, iqs %d, oqs %d\n",
ifidx_or_pfnum, num_iqueues, num_oqueues);
if_cfg.u64 = 0;
if_cfg.s.num_iqueues = num_iqueues;
if_cfg.s.num_oqueues = num_oqueues;
if_cfg.s.base_queue = base_queue;
if_cfg.s.gmx_port_id = gmx_port_id;
sc->iq_no = 0;
octeon_prepare_soft_command(octeon_dev, sc, OPCODE_NIC,
OPCODE_NIC_IF_CFG, 0,
if_cfg.u64, 0);
init_completion(&sc->complete);
sc->sc_status = OCTEON_REQUEST_PENDING;
retval = octeon_send_soft_command(octeon_dev, sc);
if (retval == IQ_SEND_FAILED) {
dev_err(&octeon_dev->pci_dev->dev,
"iq/oq config failed status: %x\n",
retval);
/* Soft instr is freed by driver in case of failure. */
octeon_free_soft_command(octeon_dev, sc);
return(-EIO);
}
/* Sleep on a wait queue till the cond flag indicates that the
* response arrived or timed-out.
*/
retval = wait_for_sc_completion_timeout(octeon_dev, sc, 0);
if (retval)
return retval;
retval = resp->status;
if (retval) {
dev_err(&octeon_dev->pci_dev->dev, "iq/oq config failed\n");
WRITE_ONCE(sc->caller_is_done, true);
goto setup_nic_dev_done;
}
snprintf(octeon_dev->fw_info.liquidio_firmware_version,
32, "%s",
resp->cfg_info.liquidio_firmware_version);
/* Verify f/w version (in case of 'auto' loading from flash) */
fw_ver = octeon_dev->fw_info.liquidio_firmware_version;
if (memcmp(LIQUIDIO_BASE_VERSION,
fw_ver,
strlen(LIQUIDIO_BASE_VERSION))) {
dev_err(&octeon_dev->pci_dev->dev,
"Unmatched firmware version. Expected %s.x, got %s.\n",
LIQUIDIO_BASE_VERSION, fw_ver);
WRITE_ONCE(sc->caller_is_done, true);
goto setup_nic_dev_done;
} else if (atomic_read(octeon_dev->adapter_fw_state) ==
FW_IS_PRELOADED) {
dev_info(&octeon_dev->pci_dev->dev,
"Using auto-loaded firmware version %s.\n",
fw_ver);
}
/* extract micro version field; point past '<maj>.<min>.' */
micro_ver = fw_ver + strlen(LIQUIDIO_BASE_VERSION) + 1;
if (kstrtoul(micro_ver, 10, µ) != 0)
micro = 0;
octeon_dev->fw_info.ver.maj = LIQUIDIO_BASE_MAJOR_VERSION;
octeon_dev->fw_info.ver.min = LIQUIDIO_BASE_MINOR_VERSION;
octeon_dev->fw_info.ver.rev = micro;
octeon_swap_8B_data((u64 *)(&resp->cfg_info),
(sizeof(struct liquidio_if_cfg_info)) >> 3);
num_iqueues = hweight64(resp->cfg_info.iqmask);
num_oqueues = hweight64(resp->cfg_info.oqmask);
if (!(num_iqueues) || !(num_oqueues)) {
dev_err(&octeon_dev->pci_dev->dev,
"Got bad iqueues (%016llx) or oqueues (%016llx) from firmware.\n",
resp->cfg_info.iqmask,
resp->cfg_info.oqmask);
WRITE_ONCE(sc->caller_is_done, true);
goto setup_nic_dev_done;
}
if (OCTEON_CN6XXX(octeon_dev)) {
max_num_queues = CFG_GET_IQ_MAX_Q(CHIP_CONF(octeon_dev,
cn6xxx));
} else if (OCTEON_CN23XX_PF(octeon_dev)) {
max_num_queues = CFG_GET_IQ_MAX_Q(CHIP_CONF(octeon_dev,
cn23xx_pf));
}
dev_dbg(&octeon_dev->pci_dev->dev,
"interface %d, iqmask %016llx, oqmask %016llx, numiqueues %d, numoqueues %d max_num_queues: %d\n",
i, resp->cfg_info.iqmask, resp->cfg_info.oqmask,
num_iqueues, num_oqueues, max_num_queues);
netdev = alloc_etherdev_mq(LIO_SIZE, max_num_queues);
if (!netdev) {
dev_err(&octeon_dev->pci_dev->dev, "Device allocation failed\n");
WRITE_ONCE(sc->caller_is_done, true);
goto setup_nic_dev_done;
}
SET_NETDEV_DEV(netdev, &octeon_dev->pci_dev->dev);
/* Associate the routines that will handle different
* netdev tasks.
*/
netdev->netdev_ops = &lionetdevops;
retval = netif_set_real_num_rx_queues(netdev, num_oqueues);
if (retval) {
dev_err(&octeon_dev->pci_dev->dev,
"setting real number rx failed\n");
WRITE_ONCE(sc->caller_is_done, true);
goto setup_nic_dev_free;
}
retval = netif_set_real_num_tx_queues(netdev, num_iqueues);
if (retval) {
dev_err(&octeon_dev->pci_dev->dev,
"setting real number tx failed\n");
WRITE_ONCE(sc->caller_is_done, true);
goto setup_nic_dev_free;
}
lio = GET_LIO(netdev);
memset(lio, 0, sizeof(struct lio));
lio->ifidx = ifidx_or_pfnum;
props = &octeon_dev->props[i];
props->gmxport = resp->cfg_info.linfo.gmxport;
props->netdev = netdev;
lio->linfo.num_rxpciq = num_oqueues;
lio->linfo.num_txpciq = num_iqueues;
for (j = 0; j < num_oqueues; j++) {
lio->linfo.rxpciq[j].u64 =
resp->cfg_info.linfo.rxpciq[j].u64;
}
for (j = 0; j < num_iqueues; j++) {
lio->linfo.txpciq[j].u64 =
resp->cfg_info.linfo.txpciq[j].u64;
}
lio->linfo.hw_addr = resp->cfg_info.linfo.hw_addr;
lio->linfo.gmxport = resp->cfg_info.linfo.gmxport;
lio->linfo.link.u64 = resp->cfg_info.linfo.link.u64;
WRITE_ONCE(sc->caller_is_done, true);
lio->msg_enable = netif_msg_init(debug, DEFAULT_MSG_ENABLE);
if (OCTEON_CN23XX_PF(octeon_dev) ||
OCTEON_CN6XXX(octeon_dev)) {
lio->dev_capability = NETIF_F_HIGHDMA
| NETIF_F_IP_CSUM
| NETIF_F_IPV6_CSUM
| NETIF_F_SG | NETIF_F_RXCSUM
| NETIF_F_GRO
| NETIF_F_TSO | NETIF_F_TSO6
| NETIF_F_LRO;
}
netif_set_gso_max_size(netdev, OCTNIC_GSO_MAX_SIZE);
/* Copy of transmit encapsulation capabilities:
* TSO, TSO6, Checksums for this device
*/
lio->enc_dev_capability = NETIF_F_IP_CSUM
| NETIF_F_IPV6_CSUM
| NETIF_F_GSO_UDP_TUNNEL
| NETIF_F_HW_CSUM | NETIF_F_SG
| NETIF_F_RXCSUM
| NETIF_F_TSO | NETIF_F_TSO6
| NETIF_F_LRO;
netdev->hw_enc_features = (lio->enc_dev_capability &
~NETIF_F_LRO);
netdev->udp_tunnel_nic_info = &liquidio_udp_tunnels;
lio->dev_capability |= NETIF_F_GSO_UDP_TUNNEL;
netdev->vlan_features = lio->dev_capability;
/* Add any unchangeable hw features */
lio->dev_capability |= NETIF_F_HW_VLAN_CTAG_FILTER |
NETIF_F_HW_VLAN_CTAG_RX |
NETIF_F_HW_VLAN_CTAG_TX;
netdev->features = (lio->dev_capability & ~NETIF_F_LRO);
netdev->hw_features = lio->dev_capability;
/*HW_VLAN_RX and HW_VLAN_FILTER is always on*/
netdev->hw_features = netdev->hw_features &
~NETIF_F_HW_VLAN_CTAG_RX;
/* MTU range: 68 - 16000 */
netdev->min_mtu = LIO_MIN_MTU_SIZE;
netdev->max_mtu = LIO_MAX_MTU_SIZE;
/* Point to the properties for octeon device to which this
* interface belongs.
*/
lio->oct_dev = octeon_dev;
lio->octprops = props;
lio->netdev = netdev;
dev_dbg(&octeon_dev->pci_dev->dev,
"if%d gmx: %d hw_addr: 0x%llx\n", i,
lio->linfo.gmxport, CVM_CAST64(lio->linfo.hw_addr));
for (j = 0; j < octeon_dev->sriov_info.max_vfs; j++) {
u8 vfmac[ETH_ALEN];
eth_random_addr(vfmac);
if (__liquidio_set_vf_mac(netdev, j, vfmac, false)) {
dev_err(&octeon_dev->pci_dev->dev,
"Error setting VF%d MAC address\n",
j);
goto setup_nic_dev_free;
}
}
/* 64-bit swap required on LE machines */
octeon_swap_8B_data(&lio->linfo.hw_addr, 1);
for (j = 0; j < 6; j++)
mac[j] = *((u8 *)(((u8 *)&lio->linfo.hw_addr) + 2 + j));
/* Copy MAC Address to OS network device structure */
eth_hw_addr_set(netdev, mac);
/* By default all interfaces on a single Octeon uses the same
* tx and rx queues
*/
lio->txq = lio->linfo.txpciq[0].s.q_no;
lio->rxq = lio->linfo.rxpciq[0].s.q_no;
if (liquidio_setup_io_queues(octeon_dev, i,
lio->linfo.num_txpciq,
lio->linfo.num_rxpciq)) {
dev_err(&octeon_dev->pci_dev->dev, "I/O queues creation failed\n");
goto setup_nic_dev_free;
}
ifstate_set(lio, LIO_IFSTATE_DROQ_OPS);
lio->tx_qsize = octeon_get_tx_qsize(octeon_dev, lio->txq);
lio->rx_qsize = octeon_get_rx_qsize(octeon_dev, lio->rxq);
if (lio_setup_glists(octeon_dev, lio, num_iqueues)) {
dev_err(&octeon_dev->pci_dev->dev,
"Gather list allocation failed\n");
goto setup_nic_dev_free;
}
/* Register ethtool support */
liquidio_set_ethtool_ops(netdev);
if (lio->oct_dev->chip_id == OCTEON_CN23XX_PF_VID)
octeon_dev->priv_flags = OCT_PRIV_FLAG_DEFAULT;
else
octeon_dev->priv_flags = 0x0;
if (netdev->features & NETIF_F_LRO)
liquidio_set_feature(netdev, OCTNET_CMD_LRO_ENABLE,
OCTNIC_LROIPV4 | OCTNIC_LROIPV6);
liquidio_set_feature(netdev, OCTNET_CMD_VLAN_FILTER_CTL,
OCTNET_CMD_VLAN_FILTER_ENABLE);
if ((debug != -1) && (debug & NETIF_MSG_HW))
liquidio_set_feature(netdev,
OCTNET_CMD_VERBOSE_ENABLE, 0);
if (setup_link_status_change_wq(netdev))
goto setup_nic_dev_free;
if ((octeon_dev->fw_info.app_cap_flags &
LIQUIDIO_TIME_SYNC_CAP) &&
setup_sync_octeon_time_wq(netdev))
goto setup_nic_dev_free;
if (setup_rx_oom_poll_fn(netdev))
goto setup_nic_dev_free;
/* Register the network device with the OS */
if (register_netdev(netdev)) {
dev_err(&octeon_dev->pci_dev->dev, "Device registration failed\n");
goto setup_nic_dev_free;
}
dev_dbg(&octeon_dev->pci_dev->dev,
"Setup NIC ifidx:%d mac:%02x%02x%02x%02x%02x%02x\n",
i, mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
netif_carrier_off(netdev);
lio->link_changes++;
ifstate_set(lio, LIO_IFSTATE_REGISTERED);
/* Sending command to firmware to enable Rx checksum offload
* by default at the time of setup of Liquidio driver for
* this device
*/
liquidio_set_rxcsum_command(netdev, OCTNET_CMD_TNL_RX_CSUM_CTL,
OCTNET_CMD_RXCSUM_ENABLE);
liquidio_set_feature(netdev, OCTNET_CMD_TNL_TX_CSUM_CTL,
OCTNET_CMD_TXCSUM_ENABLE);
dev_dbg(&octeon_dev->pci_dev->dev,
"NIC ifidx:%d Setup successful\n", i);
if (octeon_dev->subsystem_id ==
OCTEON_CN2350_25GB_SUBSYS_ID ||
octeon_dev->subsystem_id ==
OCTEON_CN2360_25GB_SUBSYS_ID) {
cur_ver = OCT_FW_VER(octeon_dev->fw_info.ver.maj,
octeon_dev->fw_info.ver.min,
octeon_dev->fw_info.ver.rev);
/* speed control unsupported in f/w older than 1.7.2 */
if (cur_ver < OCT_FW_VER(1, 7, 2)) {
dev_info(&octeon_dev->pci_dev->dev,
"speed setting not supported by f/w.");
octeon_dev->speed_setting = 25;
octeon_dev->no_speed_setting = 1;
} else {
liquidio_get_speed(lio);
}
if (octeon_dev->speed_setting == 0) {
octeon_dev->speed_setting = 25;
octeon_dev->no_speed_setting = 1;
}
} else {
octeon_dev->no_speed_setting = 1;
octeon_dev->speed_setting = 10;
}
octeon_dev->speed_boot = octeon_dev->speed_setting;
/* don't read FEC setting if unsupported by f/w (see above) */
if (octeon_dev->speed_boot == 25 &&
!octeon_dev->no_speed_setting) {
liquidio_get_fec(lio);
octeon_dev->props[lio->ifidx].fec_boot =
octeon_dev->props[lio->ifidx].fec;
}
}
device_lock(&octeon_dev->pci_dev->dev);
devlink = devlink_alloc(&liquidio_devlink_ops,
sizeof(struct lio_devlink_priv),
&octeon_dev->pci_dev->dev);
if (!devlink) {
device_unlock(&octeon_dev->pci_dev->dev);
dev_err(&octeon_dev->pci_dev->dev, "devlink alloc failed\n");
goto setup_nic_dev_free;
}
lio_devlink = devlink_priv(devlink);
lio_devlink->oct = octeon_dev;
octeon_dev->devlink = devlink;
octeon_dev->eswitch_mode = DEVLINK_ESWITCH_MODE_LEGACY;
devlink_register(devlink);
device_unlock(&octeon_dev->pci_dev->dev);
return 0;
setup_nic_dev_free:
while (i--) {
dev_err(&octeon_dev->pci_dev->dev,
"NIC ifidx:%d Setup failed\n", i);
liquidio_destroy_nic_device(octeon_dev, i);
}
setup_nic_dev_done:
return -ENODEV;
}