/********************************************************************** * 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> #include"liquidio_common.h" #include"octeon_droq.h" #include"octeon_iq.h" #include"response_manager.h" #include"octeon_device.h" #include"octeon_main.h" #include"octeon_network.h" #include"cn66xx_regs.h" #include"cn66xx_device.h" #include"cn23xx_pf_device.h" #include"cn23xx_vf_device.h"
/* For ethernet interface 0: Port cfg Attributes */
.nic_if_cfg[0] = { /* Max Txqs: Half for each of the two ports :max_iq/2 */
.max_txqs = MAX_TXQS_PER_INTF,
/* Actual configured value. Range could be: 1...max_txqs */
.num_txqs = DEF_TXQS_PER_INTF,
/* Max Rxqs: Half for each of the two ports :max_oq/2 */
.max_rxqs = MAX_RXQS_PER_INTF,
/* Actual configured value. Range could be: 1...max_rxqs */
.num_rxqs = DEF_RXQS_PER_INTF,
/* Num of desc for rx rings */
.num_rx_descs = CN6XXX_MAX_OQ_DESCRIPTORS,
/* Num of desc for tx rings */
.num_tx_descs = CN6XXX_MAX_IQ_DESCRIPTORS,
/* SKB size, We need not change buf size even for Jumbo frames. * Octeon can send jumbo frames in 4 consecutive descriptors,
*/
.rx_buf_size = CN6XXX_OQ_BUF_SIZE,
.base_queue = BASE_QUEUE_NOT_REQUESTED,
.gmx_port_id = 0,
},
.nic_if_cfg[1] = { /* Max Txqs: Half for each of the two ports :max_iq/2 */
.max_txqs = MAX_TXQS_PER_INTF,
/* Actual configured value. Range could be: 1...max_txqs */
.num_txqs = DEF_TXQS_PER_INTF,
/* Max Rxqs: Half for each of the two ports :max_oq/2 */
.max_rxqs = MAX_RXQS_PER_INTF,
/* Actual configured value. Range could be: 1...max_rxqs */
.num_rxqs = DEF_RXQS_PER_INTF,
/* Num of desc for rx rings */
.num_rx_descs = CN6XXX_MAX_OQ_DESCRIPTORS,
/* Num of desc for tx rings */
.num_tx_descs = CN6XXX_MAX_IQ_DESCRIPTORS,
/* SKB size, We need not change buf size even for Jumbo frames. * Octeon can send jumbo frames in 4 consecutive descriptors,
*/
.rx_buf_size = CN6XXX_OQ_BUF_SIZE,
.nic_if_cfg[0] = { /* Max Txqs: Half for each of the two ports :max_iq/2 */
.max_txqs = MAX_TXQS_PER_INTF,
/* Actual configured value. Range could be: 1...max_txqs */
.num_txqs = DEF_TXQS_PER_INTF,
/* Max Rxqs: Half for each of the two ports :max_oq/2 */
.max_rxqs = MAX_RXQS_PER_INTF,
/* Actual configured value. Range could be: 1...max_rxqs */
.num_rxqs = DEF_RXQS_PER_INTF,
/* Num of desc for rx rings */
.num_rx_descs = CN6XXX_MAX_OQ_DESCRIPTORS,
/* Num of desc for tx rings */
.num_tx_descs = CN6XXX_MAX_IQ_DESCRIPTORS,
/* SKB size, We need not change buf size even for Jumbo frames. * Octeon can send jumbo frames in 4 consecutive descriptors,
*/
.rx_buf_size = CN6XXX_OQ_BUF_SIZE,
.base_queue = BASE_QUEUE_NOT_REQUESTED,
.gmx_port_id = 0,
},
.nic_if_cfg[1] = { /* Max Txqs: Half for each of the two ports :max_iq/2 */
.max_txqs = MAX_TXQS_PER_INTF,
/* Actual configured value. Range could be: 1...max_txqs */
.num_txqs = DEF_TXQS_PER_INTF,
/* Max Rxqs: Half for each of the two ports :max_oq/2 */
.max_rxqs = MAX_RXQS_PER_INTF,
/* Actual configured value. Range could be: 1...max_rxqs */
.num_rxqs = DEF_RXQS_PER_INTF,
/* Num of desc for rx rings */
.num_rx_descs = CN6XXX_MAX_OQ_DESCRIPTORS,
/* Num of desc for tx rings */
.num_tx_descs = CN6XXX_MAX_IQ_DESCRIPTORS,
/* SKB size, We need not change buf size even for Jumbo frames. * Octeon can send jumbo frames in 4 consecutive descriptors,
*/
.rx_buf_size = CN6XXX_OQ_BUF_SIZE,
.base_queue = BASE_QUEUE_NOT_REQUESTED,
.gmx_port_id = 1,
},
.nic_if_cfg[2] = { /* Max Txqs: Half for each of the two ports :max_iq/2 */
.max_txqs = MAX_TXQS_PER_INTF,
/* Actual configured value. Range could be: 1...max_txqs */
.num_txqs = DEF_TXQS_PER_INTF,
/* Max Rxqs: Half for each of the two ports :max_oq/2 */
.max_rxqs = MAX_RXQS_PER_INTF,
/* Actual configured value. Range could be: 1...max_rxqs */
.num_rxqs = DEF_RXQS_PER_INTF,
/* Num of desc for rx rings */
.num_rx_descs = CN6XXX_MAX_OQ_DESCRIPTORS,
/* Num of desc for tx rings */
.num_tx_descs = CN6XXX_MAX_IQ_DESCRIPTORS,
/* SKB size, We need not change buf size even for Jumbo frames. * Octeon can send jumbo frames in 4 consecutive descriptors,
*/
.rx_buf_size = CN6XXX_OQ_BUF_SIZE,
.base_queue = BASE_QUEUE_NOT_REQUESTED,
.gmx_port_id = 2,
},
.nic_if_cfg[3] = { /* Max Txqs: Half for each of the two ports :max_iq/2 */
.max_txqs = MAX_TXQS_PER_INTF,
/* Actual configured value. Range could be: 1...max_txqs */
.num_txqs = DEF_TXQS_PER_INTF,
/* Max Rxqs: Half for each of the two ports :max_oq/2 */
.max_rxqs = MAX_RXQS_PER_INTF,
/* Actual configured value. Range could be: 1...max_rxqs */
.num_rxqs = DEF_RXQS_PER_INTF,
/* Num of desc for rx rings */
.num_rx_descs = CN6XXX_MAX_OQ_DESCRIPTORS,
/* Num of desc for tx rings */
.num_tx_descs = CN6XXX_MAX_IQ_DESCRIPTORS,
/* SKB size, We need not change buf size even for Jumbo frames. * Octeon can send jumbo frames in 4 consecutive descriptors,
*/
.rx_buf_size = CN6XXX_OQ_BUF_SIZE,
.nic_if_cfg[0] = { /* Max Txqs: Half for each of the two ports :max_iq/2 */
.max_txqs = MAX_TXQS_PER_INTF,
/* Actual configured value. Range could be: 1...max_txqs */
.num_txqs = DEF_TXQS_PER_INTF,
/* Max Rxqs: Half for each of the two ports :max_oq/2 */
.max_rxqs = MAX_RXQS_PER_INTF,
/* Actual configured value. Range could be: 1...max_rxqs */
.num_rxqs = DEF_RXQS_PER_INTF,
/* Num of desc for rx rings */
.num_rx_descs = CN6XXX_MAX_OQ_DESCRIPTORS,
/* Num of desc for tx rings */
.num_tx_descs = CN6XXX_MAX_IQ_DESCRIPTORS,
/* SKB size, We need not change buf size even for Jumbo frames. * Octeon can send jumbo frames in 4 consecutive descriptors,
*/
.rx_buf_size = CN6XXX_OQ_BUF_SIZE,
.base_queue = BASE_QUEUE_NOT_REQUESTED,
.gmx_port_id = 0,
},
.nic_if_cfg[1] = { /* Max Txqs: Half for each of the two ports :max_iq/2 */
.max_txqs = MAX_TXQS_PER_INTF,
/* Actual configured value. Range could be: 1...max_txqs */
.num_txqs = DEF_TXQS_PER_INTF,
/* Max Rxqs: Half for each of the two ports :max_oq/2 */
.max_rxqs = MAX_RXQS_PER_INTF,
/* Actual configured value. Range could be: 1...max_rxqs */
.num_rxqs = DEF_RXQS_PER_INTF,
/* Num of desc for rx rings */
.num_rx_descs = CN6XXX_MAX_OQ_DESCRIPTORS,
/* Num of desc for tx rings */
.num_tx_descs = CN6XXX_MAX_IQ_DESCRIPTORS,
/* SKB size, We need not change buf size even for Jumbo frames. * Octeon can send jumbo frames in 4 consecutive descriptors,
*/
.rx_buf_size = CN6XXX_OQ_BUF_SIZE,
/* For ethernet interface 0: Port cfg Attributes */
.nic_if_cfg[0] = { /* Max Txqs: Half for each of the two ports :max_iq/2 */
.max_txqs = MAX_TXQS_PER_INTF,
/* Actual configured value. Range could be: 1...max_txqs */
.num_txqs = DEF_TXQS_PER_INTF,
/* Max Rxqs: Half for each of the two ports :max_oq/2 */
.max_rxqs = MAX_RXQS_PER_INTF,
/* Actual configured value. Range could be: 1...max_rxqs */
.num_rxqs = DEF_RXQS_PER_INTF,
/* Num of desc for rx rings */
.num_rx_descs = CN23XX_DEFAULT_OQ_DESCRIPTORS,
/* Num of desc for tx rings */
.num_tx_descs = CN23XX_DEFAULT_IQ_DESCRIPTORS,
/* SKB size, We need not change buf size even for Jumbo frames. * Octeon can send jumbo frames in 4 consecutive descriptors,
*/
.rx_buf_size = CN23XX_OQ_BUF_SIZE,
.base_queue = BASE_QUEUE_NOT_REQUESTED,
.gmx_port_id = 0,
},
.nic_if_cfg[1] = { /* Max Txqs: Half for each of the two ports :max_iq/2 */
.max_txqs = MAX_TXQS_PER_INTF,
/* Actual configured value. Range could be: 1...max_txqs */
.num_txqs = DEF_TXQS_PER_INTF,
/* Max Rxqs: Half for each of the two ports :max_oq/2 */
.max_rxqs = MAX_RXQS_PER_INTF,
/* Actual configured value. Range could be: 1...max_rxqs */
.num_rxqs = DEF_RXQS_PER_INTF,
/* Num of desc for rx rings */
.num_rx_descs = CN23XX_DEFAULT_OQ_DESCRIPTORS,
/* Num of desc for tx rings */
.num_tx_descs = CN23XX_DEFAULT_IQ_DESCRIPTORS,
/* SKB size, We need not change buf size even for Jumbo frames. * Octeon can send jumbo frames in 4 consecutive descriptors,
*/
.rx_buf_size = CN23XX_OQ_BUF_SIZE,
/** Register a device's bus location at initialization time. * @param octeon_dev - pointer to the octeon device structure. * @param bus - PCIe bus # * @param dev - PCIe device # * @param func - PCIe function # * @param is_pf - TRUE for PF, FALSE for VF * @return reference count of device's adapter
*/ int octeon_register_device(struct octeon_device *oct, int bus, int dev, int func, int is_pf)
{ int idx, refcount;
/* Like the reference count, the f/w state is shared 'per-adapter' */
oct->adapter_fw_state = &adapter_fw_states[oct->octeon_id];
atomic_set(oct->adapter_fw_state, FW_NEEDS_TO_BE_LOADED);
spin_lock(&octeon_devices_lock); for (idx = (int)oct->octeon_id - 1; idx >= 0; idx--) { if (!octeon_device[idx]) {
dev_err(&oct->pci_dev->dev, "%s: Internal driver error, missing dev",
__func__);
spin_unlock(&octeon_devices_lock);
atomic_inc(oct->adapter_refcount); return 1; /* here, refcount is guaranteed to be 1 */
} /* If another device is at same bus/dev, use its refcounter * (and f/w state variable).
*/ if ((octeon_device[idx]->loc.bus == bus) &&
(octeon_device[idx]->loc.dev == dev)) {
oct->adapter_refcount =
octeon_device[idx]->adapter_refcount;
oct->adapter_fw_state =
octeon_device[idx]->adapter_fw_state; break;
}
}
spin_unlock(&octeon_devices_lock);
/** Deregister a device at de-initialization time. * @param octeon_dev - pointer to the octeon device structure. * @return reference count of device's adapter
*/ int octeon_deregister_device(struct octeon_device *oct)
{ int refcount;
/* this function is only for setting up the first queue */ int octeon_setup_instr_queues(struct octeon_device *oct)
{
u32 num_descs = 0;
u32 iq_no = 0; union oct_txpciq txpciq; int numa_node = dev_to_node(&oct->pci_dev->dev);
/* 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;
}
/* octeon_register_dispatch_fn * Parameters: * octeon_id - id of the octeon device. * opcode - opcode for which driver should call the registered function * subcode - subcode for which driver should call the registered function * fn - The function to call when a packet with "opcode" arrives in * octeon output queues. * fn_arg - The argument to be passed when calling function "fn". * Description: * Registers a function and its argument to be called when a packet * arrives in Octeon output queues with "opcode". * Returns: * Success: 0 * Failure: 1 * Locks: * No locks are held.
*/ int
octeon_register_dispatch_fn(struct octeon_device *oct,
u16 opcode,
u16 subcode,
octeon_dispatch_fn_t fn, void *fn_arg)
{
u32 idx;
octeon_dispatch_fn_t pfn;
u16 combined_opcode = OPCODE_SUBCODE(opcode, subcode);
idx = combined_opcode & OCTEON_OPCODE_MASK;
spin_lock_bh(&oct->dispatch.lock); /* Add dispatch function to first level of lookup table */ if (oct->dispatch.dlist[idx].opcode == 0) {
oct->dispatch.dlist[idx].opcode = combined_opcode;
oct->dispatch.dlist[idx].dispatch_fn = fn;
oct->dispatch.dlist[idx].arg = fn_arg;
oct->dispatch.count++;
spin_unlock_bh(&oct->dispatch.lock); return 0;
}
spin_unlock_bh(&oct->dispatch.lock);
/* Check if there was a function already registered for this * opcode/subcode.
*/
pfn = octeon_get_dispatch(oct, opcode, subcode); if (!pfn) { struct octeon_dispatch *dispatch;
dev_dbg(&oct->pci_dev->dev, "Adding opcode to dispatch list linked list\n");
dispatch = kmalloc(sizeof(*dispatch), GFP_KERNEL); if (!dispatch) return 1;
/* Add dispatch function to linked list of fn ptrs * at the hashed index.
*/
spin_lock_bh(&oct->dispatch.lock);
list_add(&dispatch->list, &oct->dispatch.dlist[idx].list);
oct->dispatch.count++;
spin_unlock_bh(&oct->dispatch.lock);
if (atomic_read(&oct->status) >= OCT_DEV_RUNNING) {
dev_err(&oct->pci_dev->dev, "Received CORE OK when device state is 0x%x\n",
atomic_read(&oct->status)); goto core_drv_init_err;
}
core_drv_init_err: for (i = 0; i < recv_pkt->buffer_count; i++)
recv_buffer_free(recv_pkt->buffer_ptr[i]);
octeon_free_recv_info(recv_info); return 0;
}
EXPORT_SYMBOL_GPL(octeon_core_drv_init);
int octeon_get_tx_qsize(struct octeon_device *oct, u32 q_no)
/* The windowed read happens when the LSB of the addr is written. * So write MSB first
*/
addrhi = (addr >> 32); if ((oct->chip_id == OCTEON_CN66XX) ||
(oct->chip_id == OCTEON_CN68XX) ||
(oct->chip_id == OCTEON_CN23XX_PF_VID))
addrhi |= 0x00060000;
writel(addrhi, oct->reg_list.pci_win_rd_addr_hi);
/* Read back to preserve ordering of writes */
readl(oct->reg_list.pci_win_rd_addr_hi);
/* The write happens when the LSB is written. So write MSB first. */
writel(val >> 32, oct->reg_list.pci_win_wr_data_hi); /* Read the MSB to ensure ordering of writes. */
readl(oct->reg_list.pci_win_wr_data_hi);
/* the whole thing needs to be atomic, ideally */ if (droq) {
pkts_pend = (u32)atomic_read(&droq->pkts_pending);
writel(droq->pkt_count - pkts_pend, droq->pkts_sent_reg);
droq->pkt_count = pkts_pend;
oct = droq->oct_dev;
} if (iq) {
spin_lock_bh(&iq->lock);
writel(iq->pkts_processed, iq->inst_cnt_reg);
iq->pkt_in_done -= iq->pkts_processed;
iq->pkts_processed = 0; /* this write needs to be flushed before we release the lock */
spin_unlock_bh(&iq->lock);
oct = iq->oct_dev;
} /*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) || 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*/ elseif (iq) {
instr_cnt = readq(iq->inst_cnt_reg);
writeq(((instr_cnt & 0xFFFFFFFF00000000ULL) |
CN23XX_INTR_RESEND),
iq->inst_cnt_reg);
}
}
}
EXPORT_SYMBOL_GPL(lio_enable_irq);
Messung V0.5
¤ Dauer der Verarbeitung: 0.19 Sekunden
(vorverarbeitet)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.