diff options
Diffstat (limited to 'drivers/net/ethernet/cavium/liquidio/octeon_device.c')
-rw-r--r-- | drivers/net/ethernet/cavium/liquidio/octeon_device.c | 150 |
1 files changed, 101 insertions, 49 deletions
diff --git a/drivers/net/ethernet/cavium/liquidio/octeon_device.c b/drivers/net/ethernet/cavium/liquidio/octeon_device.c index 586b68899b06..a8df493a5012 100644 --- a/drivers/net/ethernet/cavium/liquidio/octeon_device.c +++ b/drivers/net/ethernet/cavium/liquidio/octeon_device.c @@ -1,24 +1,20 @@ /********************************************************************** -* Author: Cavium, Inc. -* -* Contact: support@cavium.com -* Please include "LiquidIO" in the subject. -* -* Copyright (c) 2003-2015 Cavium, Inc. -* -* This file is free software; you can redistribute it and/or modify -* it under the terms of the GNU General Public License, Version 2, as -* published by the Free Software Foundation. -* -* This file is distributed in the hope that it will be useful, but -* AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty -* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or -* NONINFRINGEMENT. See the GNU General Public License for more -* details. -* -* This file may also be available under a different license from Cavium. -* Contact Cavium, Inc. for more information -**********************************************************************/ + * Author: Cavium, Inc. + * + * Contact: support@cavium.com + * Please include "LiquidIO" in the subject. + * + * Copyright (c) 2003-2016 Cavium, Inc. + * + * This file is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License, Version 2, as + * published by the Free Software Foundation. + * + * This file is distributed in the hope that it will be useful, but + * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or + * NONINFRINGEMENT. See the GNU General Public License for more details. + ***********************************************************************/ #include <linux/pci.h> #include <linux/netdevice.h> #include <linux/vmalloc.h> @@ -32,6 +28,7 @@ #include "cn66xx_regs.h" #include "cn66xx_device.h" #include "cn23xx_pf_device.h" +#include "cn23xx_vf_device.h" /** Default configuration * for CN66XX OCTEON Models. @@ -520,11 +517,6 @@ static struct octeon_config default_cn23xx_conf = { } }; -enum { - OCTEON_CONFIG_TYPE_DEFAULT = 0, - NUM_OCTEON_CONFS, -}; - static struct octeon_config_ptr { u32 conf_type; } oct_conf_info[MAX_OCTEON_DEVICES] = { @@ -580,15 +572,17 @@ static void *__retrieve_octeon_config_info(struct octeon_device *oct, switch (oct_conf_info[oct_id].conf_type) { case OCTEON_CONFIG_TYPE_DEFAULT: if (oct->chip_id == OCTEON_CN66XX) { - ret = (void *)&default_cn66xx_conf; + ret = &default_cn66xx_conf; } else if ((oct->chip_id == OCTEON_CN68XX) && (card_type == LIO_210NV)) { - ret = (void *)&default_cn68xx_210nv_conf; + ret = &default_cn68xx_210nv_conf; } else if ((oct->chip_id == OCTEON_CN68XX) && (card_type == LIO_410NV)) { - ret = (void *)&default_cn68xx_conf; + ret = &default_cn68xx_conf; } else if (oct->chip_id == OCTEON_CN23XX_PF_VID) { - ret = (void *)&default_cn23xx_conf; + ret = &default_cn23xx_conf; + } else if (oct->chip_id == OCTEON_CN23XX_VF_VID) { + ret = &default_cn23xx_conf; } break; default: @@ -604,6 +598,7 @@ static int __verify_octeon_config_info(struct octeon_device *oct, void *conf) case OCTEON_CN68XX: return lio_validate_cn6xxx_config_info(oct, conf); case OCTEON_CN23XX_PF_VID: + case OCTEON_CN23XX_VF_VID: return 0; default: break; @@ -649,12 +644,12 @@ void octeon_free_device_mem(struct octeon_device *oct) int i; for (i = 0; i < MAX_OCTEON_OUTPUT_QUEUES(oct); i++) { - if (oct->io_qmask.oq & (1ULL << i)) + if (oct->io_qmask.oq & BIT_ULL(i)) vfree(oct->droq[i]); } for (i = 0; i < MAX_OCTEON_INSTR_QUEUES(oct); i++) { - if (oct->io_qmask.iq & (1ULL << i)) + if (oct->io_qmask.iq & BIT_ULL(i)) vfree(oct->instr_queue[i]); } @@ -681,6 +676,9 @@ static struct octeon_device *octeon_allocate_device_mem(u32 pci_id, case OCTEON_CN23XX_PF_VID: configsize = sizeof(struct octeon_cn23xx_pf); break; + case OCTEON_CN23XX_VF_VID: + configsize = sizeof(struct octeon_cn23xx_vf); + break; default: pr_err("%s: Unknown PCI Device: 0x%x\n", __func__, @@ -756,6 +754,9 @@ octeon_allocate_ioq_vector(struct octeon_device *oct) if (OCTEON_CN23XX_PF(oct)) num_ioqs = oct->sriov_info.num_pf_rings; + else if (OCTEON_CN23XX_VF(oct)) + num_ioqs = oct->sriov_info.rings_per_vf; + size = sizeof(struct octeon_ioq_vector) * num_ioqs; oct->ioq_vector = vmalloc(size); @@ -767,6 +768,7 @@ octeon_allocate_ioq_vector(struct octeon_device *oct) ioq_vector->oct_dev = oct; ioq_vector->iq_index = i; ioq_vector->droq_index = i; + ioq_vector->mbox = oct->mbox[i]; cpu_num = i % num_online_cpus(); cpumask_set_cpu(cpu_num, &ioq_vector->affinity_mask); @@ -795,10 +797,11 @@ int octeon_setup_instr_queues(struct octeon_device *oct) if (OCTEON_CN6XXX(oct)) num_descs = - CFG_GET_NUM_DEF_TX_DESCS(CHIP_FIELD(oct, cn6xxx, conf)); + CFG_GET_NUM_DEF_TX_DESCS(CHIP_CONF(oct, cn6xxx)); else if (OCTEON_CN23XX_PF(oct)) - num_descs = CFG_GET_NUM_DEF_TX_DESCS(CHIP_FIELD(oct, cn23xx_pf, - conf)); + num_descs = CFG_GET_NUM_DEF_TX_DESCS(CHIP_CONF(oct, cn23xx_pf)); + else if (OCTEON_CN23XX_VF(oct)) + num_descs = CFG_GET_NUM_DEF_TX_DESCS(CHIP_CONF(oct, cn23xx_vf)); oct->num_iqs = 0; @@ -821,6 +824,7 @@ int octeon_setup_instr_queues(struct octeon_device *oct) if (octeon_init_instr_queue(oct, txpciq, num_descs)) { /* prevent memory leak */ vfree(oct->instr_queue[0]); + oct->instr_queue[0] = NULL; return 1; } @@ -837,14 +841,15 @@ int octeon_setup_output_queues(struct octeon_device *oct) if (OCTEON_CN6XXX(oct)) { num_descs = - CFG_GET_NUM_DEF_RX_DESCS(CHIP_FIELD(oct, cn6xxx, conf)); + CFG_GET_NUM_DEF_RX_DESCS(CHIP_CONF(oct, cn6xxx)); desc_size = - CFG_GET_DEF_RX_BUF_SIZE(CHIP_FIELD(oct, cn6xxx, conf)); + CFG_GET_DEF_RX_BUF_SIZE(CHIP_CONF(oct, cn6xxx)); } else if (OCTEON_CN23XX_PF(oct)) { - num_descs = CFG_GET_NUM_DEF_RX_DESCS(CHIP_FIELD(oct, cn23xx_pf, - conf)); - desc_size = CFG_GET_DEF_RX_BUF_SIZE(CHIP_FIELD(oct, cn23xx_pf, - conf)); + num_descs = CFG_GET_NUM_DEF_RX_DESCS(CHIP_CONF(oct, cn23xx_pf)); + desc_size = CFG_GET_DEF_RX_BUF_SIZE(CHIP_CONF(oct, cn23xx_pf)); + } else if (OCTEON_CN23XX_VF(oct)) { + num_descs = CFG_GET_NUM_DEF_RX_DESCS(CHIP_CONF(oct, cn23xx_vf)); + desc_size = CFG_GET_DEF_RX_BUF_SIZE(CHIP_CONF(oct, cn23xx_vf)); } oct->num_oqs = 0; oct->droq[0] = vmalloc_node(sizeof(*oct->droq[0]), numa_node); @@ -853,19 +858,63 @@ int octeon_setup_output_queues(struct octeon_device *oct) if (!oct->droq[0]) return 1; - if (octeon_init_droq(oct, oq_no, num_descs, desc_size, NULL)) + if (octeon_init_droq(oct, oq_no, num_descs, desc_size, NULL)) { + vfree(oct->droq[oq_no]); + oct->droq[oq_no] = NULL; return 1; + } oct->num_oqs++; return 0; } -void octeon_set_io_queues_off(struct octeon_device *oct) +int octeon_set_io_queues_off(struct octeon_device *oct) { + int loop = BUSY_READING_REG_VF_LOOP_COUNT; + if (OCTEON_CN6XXX(oct)) { octeon_write_csr(oct, CN6XXX_SLI_PKT_INSTR_ENB, 0); octeon_write_csr(oct, CN6XXX_SLI_PKT_OUT_ENB, 0); + } else if (oct->chip_id == OCTEON_CN23XX_VF_VID) { + u32 q_no; + + /* IOQs will already be in reset. + * If RST bit is set, wait for quiet bit to be set. + * Once quiet bit is set, clear the RST bit. + */ + for (q_no = 0; q_no < oct->sriov_info.rings_per_vf; q_no++) { + u64 reg_val = octeon_read_csr64( + oct, CN23XX_VF_SLI_IQ_PKT_CONTROL64(q_no)); + + while ((reg_val & CN23XX_PKT_INPUT_CTL_RST) && + !(reg_val & CN23XX_PKT_INPUT_CTL_QUIET) && + loop) { + reg_val = octeon_read_csr64( + oct, CN23XX_SLI_IQ_PKT_CONTROL64(q_no)); + loop--; + } + if (!loop) { + dev_err(&oct->pci_dev->dev, + "clearing the reset reg failed or setting the quiet reg failed for qno: %u\n", + q_no); + return -1; + } + + reg_val = reg_val & ~CN23XX_PKT_INPUT_CTL_RST; + octeon_write_csr64(oct, + CN23XX_SLI_IQ_PKT_CONTROL64(q_no), + reg_val); + + reg_val = octeon_read_csr64( + oct, CN23XX_SLI_IQ_PKT_CONTROL64(q_no)); + if (reg_val & CN23XX_PKT_INPUT_CTL_RST) { + dev_err(&oct->pci_dev->dev, + "unable to reset qno %u\n", q_no); + return -1; + } + } } + return 0; } void octeon_set_droq_pkt_op(struct octeon_device *oct, @@ -1070,10 +1119,10 @@ int octeon_core_drv_init(struct octeon_recv_info *recv_info, void *buf) if (OCTEON_CN6XXX(oct)) num_nic_ports = - CFG_GET_NUM_NIC_PORTS(CHIP_FIELD(oct, cn6xxx, conf)); + CFG_GET_NUM_NIC_PORTS(CHIP_CONF(oct, cn6xxx)); else if (OCTEON_CN23XX_PF(oct)) num_nic_ports = - CFG_GET_NUM_NIC_PORTS(CHIP_FIELD(oct, cn23xx_pf, conf)); + CFG_GET_NUM_NIC_PORTS(CHIP_CONF(oct, cn23xx_pf)); if (atomic_read(&oct->status) >= OCT_DEV_RUNNING) { dev_err(&oct->pci_dev->dev, "Received CORE OK when device state is 0x%x\n", @@ -1143,7 +1192,7 @@ int octeon_get_tx_qsize(struct octeon_device *oct, u32 q_no) { if (oct && (q_no < MAX_OCTEON_INSTR_QUEUES(oct)) && - (oct->io_qmask.iq & (1ULL << q_no))) + (oct->io_qmask.iq & BIT_ULL(q_no))) return oct->instr_queue[q_no]->max_count; return -1; @@ -1152,7 +1201,7 @@ int octeon_get_tx_qsize(struct octeon_device *oct, u32 q_no) int octeon_get_rx_qsize(struct octeon_device *oct, u32 q_no) { if (oct && (q_no < MAX_OCTEON_OUTPUT_QUEUES(oct)) && - (oct->io_qmask.oq & (1ULL << q_no))) + (oct->io_qmask.oq & BIT_ULL(q_no))) return oct->droq[q_no]->max_count; return -1; } @@ -1168,10 +1217,13 @@ struct octeon_config *octeon_get_conf(struct octeon_device *oct) if (OCTEON_CN6XXX(oct)) { default_oct_conf = - (struct octeon_config *)(CHIP_FIELD(oct, cn6xxx, conf)); + (struct octeon_config *)(CHIP_CONF(oct, cn6xxx)); } else if (OCTEON_CN23XX_PF(oct)) { default_oct_conf = (struct octeon_config *) - (CHIP_FIELD(oct, cn23xx_pf, conf)); + (CHIP_CONF(oct, cn23xx_pf)); + } else if (OCTEON_CN23XX_VF(oct)) { + default_oct_conf = (struct octeon_config *) + (CHIP_CONF(oct, cn23xx_vf)); } return default_oct_conf; } @@ -1322,7 +1374,7 @@ void lio_enable_irq(struct octeon_droq *droq, struct octeon_instr_queue *iq) /*write resend. Writing RESEND in SLI_PKTX_CNTS should be enough *to trigger tx interrupts as well, if they are pending. */ - if (oct && OCTEON_CN23XX_PF(oct)) { + if (oct && (OCTEON_CN23XX_PF(oct) || OCTEON_CN23XX_VF(oct))) { if (droq) writeq(CN23XX_INTR_RESEND, droq->pkts_sent_reg); /*we race with firmrware here. read and write the IN_DONE_CNTS*/ |