Commit dba47afd authored by David S. Miller's avatar David S. Miller

Merge branch 'octeon_ep-driver'

Veerasenareddy Burru says:

====================
Add octeon_ep driver

This driver implements networking functionality of Marvell's Octeon
PCI Endpoint NIC.

This driver support following devices:
 * Network controller: Cavium, Inc. Device b200

V4 -> V5:
   - Fix warnings reported by clang.
   - Address comments from community reviews.

V3 -> V4:
   - Fix warnings and errors reported by "make W=1 C=1".

V2 -> V3:
   - Fix warnings and errors reported by kernel test robot:
     "Reported-by: kernel test robot <lkp@intel.com>"

V1 -> V2:
    - Address review comments on original patch series.
    - Divide PATCH 1/4 from the original series into 4 patches in
      v2 patch series: PATCH 1/7 to PATCH 4/7.
    - Fix clang build errors.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 92716869 5cc256e7
......@@ -39,6 +39,7 @@ Contents:
intel/iavf
intel/ice
marvell/octeontx2
marvell/octeon_ep
mellanox/mlx5
microsoft/netvsc
neterion/s2io
......
.. SPDX-License-Identifier: GPL-2.0+
====================================================================
Linux kernel networking driver for Marvell's Octeon PCI Endpoint NIC
====================================================================
Network driver for Marvell's Octeon PCI EndPoint NIC.
Copyright (c) 2020 Marvell International Ltd.
Contents
========
- `Overview`_
- `Supported Devices`_
- `Interface Control`_
Overview
========
This driver implements networking functionality of Marvell's Octeon PCI
EndPoint NIC.
Supported Devices
=================
Currently, this driver support following devices:
* Network controller: Cavium, Inc. Device b200
Interface Control
=================
Network Interface control like changing mtu, link speed, link down/up are
done by writing command to mailbox command queue, a mailbox interface
implemented through a reserved region in BAR4.
This driver writes the commands into the mailbox and the firmware on the
Octeon device processes them. The firmware also sends unsolicited notifications
to driver for events suchs as link change, through notification queue
implemented as part of mailbox interface.
......@@ -11828,6 +11828,13 @@ S: Supported
F: Documentation/devicetree/bindings/mmc/marvell,xenon-sdhci.txt
F: drivers/mmc/host/sdhci-xenon*
MARVELL OCTEON ENDPOINT DRIVER
M: Veerasenareddy Burru <vburru@marvell.com>
M: Abhijit Ayarekar <aayarekar@marvell.com>
L: netdev@vger.kernel.org
S: Supported
F: drivers/net/ethernet/marvell/octeon_ep
MATROX FRAMEBUFFER DRIVER
L: linux-fbdev@vger.kernel.org
S: Orphan
......
......@@ -177,6 +177,7 @@ config SKY2_DEBUG
source "drivers/net/ethernet/marvell/octeontx2/Kconfig"
source "drivers/net/ethernet/marvell/octeon_ep/Kconfig"
source "drivers/net/ethernet/marvell/prestera/Kconfig"
endif # NET_VENDOR_MARVELL
......@@ -11,5 +11,6 @@ obj-$(CONFIG_MVPP2) += mvpp2/
obj-$(CONFIG_PXA168_ETH) += pxa168_eth.o
obj-$(CONFIG_SKGE) += skge.o
obj-$(CONFIG_SKY2) += sky2.o
obj-y += octeon_ep/
obj-y += octeontx2/
obj-y += prestera/
# SPDX-License-Identifier: GPL-2.0-only
#
# Marvell's Octeon PCI Endpoint NIC Driver Configuration
#
config OCTEON_EP
tristate "Marvell Octeon PCI Endpoint NIC Driver"
depends on 64BIT
depends on PCI
depends on PTP_1588_CLOCK_OPTIONAL
help
This driver supports networking functionality of Marvell's
Octeon PCI Endpoint NIC.
To know the list of devices supported by this driver, refer
documentation in
<file:Documentation/networking/device_drivers/ethernet/marvell/octeon_ep.rst>.
To compile this drivers as a module, choose M here. Name of the
module is octeon_ep.
# SPDX-License-Identifier: GPL-2.0
#
# Network driver for Marvell's Octeon PCI Endpoint NIC
#
obj-$(CONFIG_OCTEON_EP) += octeon_ep.o
octeon_ep-y := octep_main.o octep_cn9k_pf.o octep_tx.o octep_rx.o \
octep_ethtool.o octep_ctrl_mbox.o octep_ctrl_net.o
This diff is collapsed.
/* SPDX-License-Identifier: GPL-2.0 */
/* Marvell Octeon EP (EndPoint) Ethernet Driver
*
* Copyright (C) 2020 Marvell.
*
*/
#ifndef _OCTEP_CONFIG_H_
#define _OCTEP_CONFIG_H_
/* Tx instruction types by length */
#define OCTEP_32BYTE_INSTR 32
#define OCTEP_64BYTE_INSTR 64
/* Tx Queue: maximum descriptors per ring */
#define OCTEP_IQ_MAX_DESCRIPTORS 1024
/* Minimum input (Tx) requests to be enqueued to ring doorbell */
#define OCTEP_DB_MIN 1
/* Packet threshold for Tx queue interrupt */
#define OCTEP_IQ_INTR_THRESHOLD 0x0
/* Rx Queue: maximum descriptors per ring */
#define OCTEP_OQ_MAX_DESCRIPTORS 1024
/* Rx buffer size: Use page size buffers.
* Build skb from allocated page buffer once the packet is received.
* When a gathered packet is received, make head page as skb head and
* page buffers in consecutive Rx descriptors as fragments.
*/
#define OCTEP_OQ_BUF_SIZE (SKB_WITH_OVERHEAD(PAGE_SIZE))
#define OCTEP_OQ_PKTS_PER_INTR 128
#define OCTEP_OQ_REFILL_THRESHOLD (OCTEP_OQ_MAX_DESCRIPTORS / 4)
#define OCTEP_OQ_INTR_PKT_THRESHOLD 1
#define OCTEP_OQ_INTR_TIME_THRESHOLD 10
#define OCTEP_MSIX_NAME_SIZE (IFNAMSIZ + 32)
/* Tx Queue wake threshold
* wakeup a stopped Tx queue if minimum 2 descriptors are available.
* Even a skb with fragments consume only one Tx queue descriptor entry.
*/
#define OCTEP_WAKE_QUEUE_THRESHOLD 2
/* Minimum MTU supported by Octeon network interface */
#define OCTEP_MIN_MTU ETH_MIN_MTU
/* Maximum MTU supported by Octeon interface*/
#define OCTEP_MAX_MTU (10000 - (ETH_HLEN + ETH_FCS_LEN))
/* Default MTU */
#define OCTEP_DEFAULT_MTU 1500
/* Macros to get octeon config params */
#define CFG_GET_IQ_CFG(cfg) ((cfg)->iq)
#define CFG_GET_IQ_NUM_DESC(cfg) ((cfg)->iq.num_descs)
#define CFG_GET_IQ_INSTR_TYPE(cfg) ((cfg)->iq.instr_type)
#define CFG_GET_IQ_PKIND(cfg) ((cfg)->iq.pkind)
#define CFG_GET_IQ_INSTR_SIZE(cfg) (64)
#define CFG_GET_IQ_DB_MIN(cfg) ((cfg)->iq.db_min)
#define CFG_GET_IQ_INTR_THRESHOLD(cfg) ((cfg)->iq.intr_threshold)
#define CFG_GET_OQ_NUM_DESC(cfg) ((cfg)->oq.num_descs)
#define CFG_GET_OQ_BUF_SIZE(cfg) ((cfg)->oq.buf_size)
#define CFG_GET_OQ_REFILL_THRESHOLD(cfg) ((cfg)->oq.refill_threshold)
#define CFG_GET_OQ_INTR_PKT(cfg) ((cfg)->oq.oq_intr_pkt)
#define CFG_GET_OQ_INTR_TIME(cfg) ((cfg)->oq.oq_intr_time)
#define CFG_GET_PORTS_MAX_IO_RINGS(cfg) ((cfg)->pf_ring_cfg.max_io_rings)
#define CFG_GET_PORTS_ACTIVE_IO_RINGS(cfg) ((cfg)->pf_ring_cfg.active_io_rings)
#define CFG_GET_PORTS_PF_SRN(cfg) ((cfg)->pf_ring_cfg.srn)
#define CFG_GET_DPI_PKIND(cfg) ((cfg)->core_cfg.dpi_pkind)
#define CFG_GET_CORE_TICS_PER_US(cfg) ((cfg)->core_cfg.core_tics_per_us)
#define CFG_GET_COPROC_TICS_PER_US(cfg) ((cfg)->core_cfg.coproc_tics_per_us)
#define CFG_GET_MAX_VFS(cfg) ((cfg)->sriov_cfg.max_vfs)
#define CFG_GET_ACTIVE_VFS(cfg) ((cfg)->sriov_cfg.active_vfs)
#define CFG_GET_MAX_RPVF(cfg) ((cfg)->sriov_cfg.max_rings_per_vf)
#define CFG_GET_ACTIVE_RPVF(cfg) ((cfg)->sriov_cfg.active_rings_per_vf)
#define CFG_GET_VF_SRN(cfg) ((cfg)->sriov_cfg.vf_srn)
#define CFG_GET_IOQ_MSIX(cfg) ((cfg)->msix_cfg.ioq_msix)
#define CFG_GET_NON_IOQ_MSIX(cfg) ((cfg)->msix_cfg.non_ioq_msix)
#define CFG_GET_NON_IOQ_MSIX_NAMES(cfg) ((cfg)->msix_cfg.non_ioq_msix_names)
#define CFG_GET_CTRL_MBOX_MEM_ADDR(cfg) ((cfg)->ctrl_mbox_cfg.barmem_addr)
/* Hardware Tx Queue configuration. */
struct octep_iq_config {
/* Size of the Input queue (number of commands) */
u16 num_descs;
/* Command size - 32 or 64 bytes */
u16 instr_type;
/* pkind for packets sent to Octeon */
u16 pkind;
/* Minimum number of commands pending to be posted to Octeon before driver
* hits the Input queue doorbell.
*/
u16 db_min;
/* Trigger the IQ interrupt when processed cmd count reaches
* this level.
*/
u32 intr_threshold;
};
/* Hardware Rx Queue configuration. */
struct octep_oq_config {
/* Size of Output queue (number of descriptors) */
u16 num_descs;
/* Size of buffer in this Output queue. */
u16 buf_size;
/* The number of buffers that were consumed during packet processing
* by the driver on this Output queue before the driver attempts to
* replenish the descriptor ring with new buffers.
*/
u16 refill_threshold;
/* Interrupt Coalescing (Packet Count). Octeon will interrupt the host
* only if it sent as many packets as specified by this field.
* The driver usually does not use packet count interrupt coalescing.
*/
u32 oq_intr_pkt;
/* Interrupt Coalescing (Time Interval). Octeon will interrupt the host
* if at least one packet was sent in the time interval specified by
* this field. The driver uses time interval interrupt coalescing by
* default. The time is specified in microseconds.
*/
u32 oq_intr_time;
};
/* Tx/Rx configuration */
struct octep_pf_ring_config {
/* Max number of IOQs */
u16 max_io_rings;
/* Number of active IOQs */
u16 active_io_rings;
/* Starting IOQ number: this changes based on which PEM is used */
u16 srn;
};
/* Octeon Hardware SRIOV config */
struct octep_sriov_config {
/* Max number of VF devices supported */
u16 max_vfs;
/* Number of VF devices enabled */
u16 active_vfs;
/* Max number of rings assigned to VF */
u8 max_rings_per_vf;
/* Number of rings enabled per VF */
u8 active_rings_per_vf;
/* starting ring number of VF's: ring-0 of VF-0 of the PF */
u16 vf_srn;
};
/* Octeon MSI-x config. */
struct octep_msix_config {
/* Number of IOQ interrupts */
u16 ioq_msix;
/* Number of Non IOQ interrupts */
u16 non_ioq_msix;
/* Names of Non IOQ interrupts */
char **non_ioq_msix_names;
};
struct octep_ctrl_mbox_config {
/* Barmem address for control mbox */
void __iomem *barmem_addr;
};
/* Data Structure to hold configuration limits and active config */
struct octep_config {
/* Input Queue attributes. */
struct octep_iq_config iq;
/* Output Queue attributes. */
struct octep_oq_config oq;
/* NIC Port Configuration */
struct octep_pf_ring_config pf_ring_cfg;
/* SRIOV configuration of the PF */
struct octep_sriov_config sriov_cfg;
/* MSI-X interrupt config */
struct octep_msix_config msix_cfg;
/* ctrl mbox config */
struct octep_ctrl_mbox_config ctrl_mbox_cfg;
};
#endif /* _OCTEP_CONFIG_H_ */
// SPDX-License-Identifier: GPL-2.0
/* Marvell Octeon EP (EndPoint) Ethernet Driver
*
* Copyright (C) 2020 Marvell.
*
*/
#include <linux/types.h>
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/mutex.h>
#include <linux/jiffies.h>
#include <linux/sched.h>
#include <linux/sched/signal.h>
#include <linux/io.h>
#include <linux/pci.h>
#include <linux/etherdevice.h>
#include "octep_ctrl_mbox.h"
#include "octep_config.h"
#include "octep_main.h"
/* Timeout in msecs for message response */
#define OCTEP_CTRL_MBOX_MSG_TIMEOUT_MS 100
/* Time in msecs to wait for message response */
#define OCTEP_CTRL_MBOX_MSG_WAIT_MS 10
#define OCTEP_CTRL_MBOX_INFO_MAGIC_NUM_OFFSET(m) (m)
#define OCTEP_CTRL_MBOX_INFO_BARMEM_SZ_OFFSET(m) ((m) + 8)
#define OCTEP_CTRL_MBOX_INFO_HOST_VERSION_OFFSET(m) ((m) + 16)
#define OCTEP_CTRL_MBOX_INFO_HOST_STATUS_OFFSET(m) ((m) + 24)
#define OCTEP_CTRL_MBOX_INFO_FW_VERSION_OFFSET(m) ((m) + 136)
#define OCTEP_CTRL_MBOX_INFO_FW_STATUS_OFFSET(m) ((m) + 144)
#define OCTEP_CTRL_MBOX_H2FQ_INFO_OFFSET(m) ((m) + OCTEP_CTRL_MBOX_INFO_SZ)
#define OCTEP_CTRL_MBOX_H2FQ_PROD_OFFSET(m) (OCTEP_CTRL_MBOX_H2FQ_INFO_OFFSET(m))
#define OCTEP_CTRL_MBOX_H2FQ_CONS_OFFSET(m) ((OCTEP_CTRL_MBOX_H2FQ_INFO_OFFSET(m)) + 4)
#define OCTEP_CTRL_MBOX_H2FQ_ELEM_SZ_OFFSET(m) ((OCTEP_CTRL_MBOX_H2FQ_INFO_OFFSET(m)) + 8)
#define OCTEP_CTRL_MBOX_H2FQ_ELEM_CNT_OFFSET(m) ((OCTEP_CTRL_MBOX_H2FQ_INFO_OFFSET(m)) + 12)
#define OCTEP_CTRL_MBOX_F2HQ_INFO_OFFSET(m) ((m) + \
OCTEP_CTRL_MBOX_INFO_SZ + \
OCTEP_CTRL_MBOX_H2FQ_INFO_SZ)
#define OCTEP_CTRL_MBOX_F2HQ_PROD_OFFSET(m) (OCTEP_CTRL_MBOX_F2HQ_INFO_OFFSET(m))
#define OCTEP_CTRL_MBOX_F2HQ_CONS_OFFSET(m) ((OCTEP_CTRL_MBOX_F2HQ_INFO_OFFSET(m)) + 4)
#define OCTEP_CTRL_MBOX_F2HQ_ELEM_SZ_OFFSET(m) ((OCTEP_CTRL_MBOX_F2HQ_INFO_OFFSET(m)) + 8)
#define OCTEP_CTRL_MBOX_F2HQ_ELEM_CNT_OFFSET(m) ((OCTEP_CTRL_MBOX_F2HQ_INFO_OFFSET(m)) + 12)
#define OCTEP_CTRL_MBOX_Q_OFFSET(m, i) ((m) + \
(sizeof(struct octep_ctrl_mbox_msg) * (i)))
static u32 octep_ctrl_mbox_circq_inc(u32 index, u32 mask)
{
return (index + 1) & mask;
}
static u32 octep_ctrl_mbox_circq_space(u32 pi, u32 ci, u32 mask)
{
return mask - ((pi - ci) & mask);
}
static u32 octep_ctrl_mbox_circq_depth(u32 pi, u32 ci, u32 mask)
{
return ((pi - ci) & mask);
}
int octep_ctrl_mbox_init(struct octep_ctrl_mbox *mbox)
{
u64 version, magic_num, status;
if (!mbox)
return -EINVAL;
if (!mbox->barmem) {
pr_info("octep_ctrl_mbox : Invalid barmem %p\n", mbox->barmem);
return -EINVAL;
}
magic_num = readq(OCTEP_CTRL_MBOX_INFO_MAGIC_NUM_OFFSET(mbox->barmem));
if (magic_num != OCTEP_CTRL_MBOX_MAGIC_NUMBER) {
pr_info("octep_ctrl_mbox : Invalid magic number %llx\n", magic_num);
return -EINVAL;
}
version = readq(OCTEP_CTRL_MBOX_INFO_FW_VERSION_OFFSET(mbox->barmem));
if (version != OCTEP_DRV_VERSION) {
pr_info("octep_ctrl_mbox : Firmware version mismatch %llx != %x\n",
version, OCTEP_DRV_VERSION);
return -EINVAL;
}
status = readq(OCTEP_CTRL_MBOX_INFO_FW_STATUS_OFFSET(mbox->barmem));
if (status != OCTEP_CTRL_MBOX_STATUS_READY) {
pr_info("octep_ctrl_mbox : Firmware is not ready.\n");
return -EINVAL;
}
mbox->barmem_sz = readl(OCTEP_CTRL_MBOX_INFO_BARMEM_SZ_OFFSET(mbox->barmem));
writeq(mbox->version, OCTEP_CTRL_MBOX_INFO_HOST_VERSION_OFFSET(mbox->barmem));
writeq(OCTEP_CTRL_MBOX_STATUS_INIT, OCTEP_CTRL_MBOX_INFO_HOST_STATUS_OFFSET(mbox->barmem));
mbox->h2fq.elem_cnt = readl(OCTEP_CTRL_MBOX_H2FQ_ELEM_CNT_OFFSET(mbox->barmem));
mbox->h2fq.elem_sz = readl(OCTEP_CTRL_MBOX_H2FQ_ELEM_SZ_OFFSET(mbox->barmem));
mbox->h2fq.mask = (mbox->h2fq.elem_cnt - 1);
mutex_init(&mbox->h2fq_lock);
mbox->f2hq.elem_cnt = readl(OCTEP_CTRL_MBOX_F2HQ_ELEM_CNT_OFFSET(mbox->barmem));
mbox->f2hq.elem_sz = readl(OCTEP_CTRL_MBOX_F2HQ_ELEM_SZ_OFFSET(mbox->barmem));
mbox->f2hq.mask = (mbox->f2hq.elem_cnt - 1);
mutex_init(&mbox->f2hq_lock);
mbox->h2fq.hw_prod = OCTEP_CTRL_MBOX_H2FQ_PROD_OFFSET(mbox->barmem);
mbox->h2fq.hw_cons = OCTEP_CTRL_MBOX_H2FQ_CONS_OFFSET(mbox->barmem);
mbox->h2fq.hw_q = mbox->barmem +
OCTEP_CTRL_MBOX_INFO_SZ +
OCTEP_CTRL_MBOX_H2FQ_INFO_SZ +
OCTEP_CTRL_MBOX_F2HQ_INFO_SZ;
mbox->f2hq.hw_prod = OCTEP_CTRL_MBOX_F2HQ_PROD_OFFSET(mbox->barmem);
mbox->f2hq.hw_cons = OCTEP_CTRL_MBOX_F2HQ_CONS_OFFSET(mbox->barmem);
mbox->f2hq.hw_q = mbox->h2fq.hw_q +
((mbox->h2fq.elem_sz + sizeof(union octep_ctrl_mbox_msg_hdr)) *
mbox->h2fq.elem_cnt);
/* ensure ready state is seen after everything is initialized */
wmb();
writeq(OCTEP_CTRL_MBOX_STATUS_READY, OCTEP_CTRL_MBOX_INFO_HOST_STATUS_OFFSET(mbox->barmem));
pr_info("Octep ctrl mbox : Init successful.\n");
return 0;
}
int octep_ctrl_mbox_send(struct octep_ctrl_mbox *mbox, struct octep_ctrl_mbox_msg *msg)
{
unsigned long timeout = msecs_to_jiffies(OCTEP_CTRL_MBOX_MSG_TIMEOUT_MS);
unsigned long period = msecs_to_jiffies(OCTEP_CTRL_MBOX_MSG_WAIT_MS);
struct octep_ctrl_mbox_q *q;
unsigned long expire;
u64 *mbuf, *word0;
u8 __iomem *qidx;
u16 pi, ci;
int i;
if (!mbox || !msg)
return -EINVAL;
q = &mbox->h2fq;
pi = readl(q->hw_prod);
ci = readl(q->hw_cons);
if (!octep_ctrl_mbox_circq_space(pi, ci, q->mask))
return -ENOMEM;
qidx = OCTEP_CTRL_MBOX_Q_OFFSET(q->hw_q, pi);
mbuf = (u64 *)msg->msg;
word0 = &msg->hdr.word0;
mutex_lock(&mbox->h2fq_lock);
for (i = 1; i <= msg->hdr.sizew; i++)
writeq(*mbuf++, (qidx + (i * 8)));
writeq(*word0, qidx);
pi = octep_ctrl_mbox_circq_inc(pi, q->mask);
writel(pi, q->hw_prod);
mutex_unlock(&mbox->h2fq_lock);
/* don't check for notification response */
if (msg->hdr.flags & OCTEP_CTRL_MBOX_MSG_HDR_FLAG_NOTIFY)
return 0;
expire = jiffies + timeout;
while (true) {
*word0 = readq(qidx);
if (msg->hdr.flags == OCTEP_CTRL_MBOX_MSG_HDR_FLAG_RESP)
break;
schedule_timeout_interruptible(period);
if (signal_pending(current) || time_after(jiffies, expire)) {
pr_info("octep_ctrl_mbox: Timed out\n");
return -EBUSY;
}
}
mbuf = (u64 *)msg->msg;
for (i = 1; i <= msg->hdr.sizew; i++)
*mbuf++ = readq(qidx + (i * 8));
return 0;
}
int octep_ctrl_mbox_recv(struct octep_ctrl_mbox *mbox, struct octep_ctrl_mbox_msg *msg)
{
struct octep_ctrl_mbox_q *q;
u32 count, pi, ci;
u8 __iomem *qidx;
u64 *mbuf;
int i;
if (!mbox || !msg)
return -EINVAL;
q = &mbox->f2hq;
pi = readl(q->hw_prod);
ci = readl(q->hw_cons);
count = octep_ctrl_mbox_circq_depth(pi, ci, q->mask);
if (!count)
return -EAGAIN;
qidx = OCTEP_CTRL_MBOX_Q_OFFSET(q->hw_q, ci);
mbuf = (u64 *)msg->msg;
mutex_lock(&mbox->f2hq_lock);
msg->hdr.word0 = readq(qidx);
for (i = 1; i <= msg->hdr.sizew; i++)
*mbuf++ = readq(qidx + (i * 8));
ci = octep_ctrl_mbox_circq_inc(ci, q->mask);
writel(ci, q->hw_cons);
mutex_unlock(&mbox->f2hq_lock);
if (msg->hdr.flags != OCTEP_CTRL_MBOX_MSG_HDR_FLAG_REQ || !mbox->process_req)
return 0;
mbox->process_req(mbox->user_ctx, msg);
mbuf = (u64 *)msg->msg;
for (i = 1; i <= msg->hdr.sizew; i++)
writeq(*mbuf++, (qidx + (i * 8)));
writeq(msg->hdr.word0, qidx);
return 0;
}
int octep_ctrl_mbox_uninit(struct octep_ctrl_mbox *mbox)
{
if (!mbox)
return -EINVAL;
writeq(OCTEP_CTRL_MBOX_STATUS_UNINIT,
OCTEP_CTRL_MBOX_INFO_HOST_STATUS_OFFSET(mbox->barmem));
/* ensure uninit state is written before uninitialization */
wmb();
mutex_destroy(&mbox->h2fq_lock);
mutex_destroy(&mbox->f2hq_lock);
writeq(OCTEP_CTRL_MBOX_STATUS_INVALID,
OCTEP_CTRL_MBOX_INFO_HOST_STATUS_OFFSET(mbox->barmem));
writeq(0, OCTEP_CTRL_MBOX_INFO_HOST_VERSION_OFFSET(mbox->barmem));
pr_info("Octep ctrl mbox : Uninit successful.\n");
return 0;
}
/* SPDX-License-Identifier: GPL-2.0 */
/* Marvell Octeon EP (EndPoint) Ethernet Driver
*
* Copyright (C) 2020 Marvell.
*
*/
#ifndef __OCTEP_CTRL_MBOX_H__
#define __OCTEP_CTRL_MBOX_H__
/* barmem structure
* |===========================================|
* |Info (16 + 120 + 120 = 256 bytes) |
* |-------------------------------------------|
* |magic number (8 bytes) |
* |bar memory size (4 bytes) |
* |reserved (4 bytes) |
* |-------------------------------------------|
* |host version (8 bytes) |
* |host status (8 bytes) |
* |host reserved (104 bytes) |
* |-------------------------------------------|
* |fw version (8 bytes) |
* |fw status (8 bytes) |
* |fw reserved (104 bytes) |
* |===========================================|
* |Host to Fw Queue info (16 bytes) |
* |-------------------------------------------|
* |producer index (4 bytes) |
* |consumer index (4 bytes) |
* |element size (4 bytes) |
* |element count (4 bytes) |
* |===========================================|
* |Fw to Host Queue info (16 bytes) |
* |-------------------------------------------|
* |producer index (4 bytes) |
* |consumer index (4 bytes) |
* |element size (4 bytes) |
* |element count (4 bytes) |
* |===========================================|
* |Host to Fw Queue |
* |-------------------------------------------|
* |((elem_sz + hdr(8 bytes)) * elem_cnt) bytes|
* |===========================================|
* |===========================================|
* |Fw to Host Queue |
* |-------------------------------------------|
* |((elem_sz + hdr(8 bytes)) * elem_cnt) bytes|
* |===========================================|
*/
#define OCTEP_CTRL_MBOX_MAGIC_NUMBER 0xdeaddeadbeefbeefull
/* Size of mbox info in bytes */
#define OCTEP_CTRL_MBOX_INFO_SZ 256
/* Size of mbox host to target queue info in bytes */
#define OCTEP_CTRL_MBOX_H2FQ_INFO_SZ 16
/* Size of mbox target to host queue info in bytes */
#define OCTEP_CTRL_MBOX_F2HQ_INFO_SZ 16
/* Size of mbox queue in bytes */
#define OCTEP_CTRL_MBOX_Q_SZ(sz, cnt) (((sz) + 8) * (cnt))
/* Size of mbox in bytes */
#define OCTEP_CTRL_MBOX_SZ(hsz, hcnt, fsz, fcnt) (OCTEP_CTRL_MBOX_INFO_SZ + \
OCTEP_CTRL_MBOX_H2FQ_INFO_SZ + \
OCTEP_CTRL_MBOX_F2HQ_INFO_SZ + \
OCTEP_CTRL_MBOX_Q_SZ(hsz, hcnt) + \
OCTEP_CTRL_MBOX_Q_SZ(fsz, fcnt))
/* Valid request message */
#define OCTEP_CTRL_MBOX_MSG_HDR_FLAG_REQ BIT(0)
/* Valid response message */
#define OCTEP_CTRL_MBOX_MSG_HDR_FLAG_RESP BIT(1)
/* Valid notification, no response required */
#define OCTEP_CTRL_MBOX_MSG_HDR_FLAG_NOTIFY BIT(2)
enum octep_ctrl_mbox_status {
OCTEP_CTRL_MBOX_STATUS_INVALID = 0,
OCTEP_CTRL_MBOX_STATUS_INIT,
OCTEP_CTRL_MBOX_STATUS_READY,
OCTEP_CTRL_MBOX_STATUS_UNINIT
};
/* mbox message */
union octep_ctrl_mbox_msg_hdr {
u64 word0;
struct {
/* OCTEP_CTRL_MBOX_MSG_HDR_FLAG_* */
u32 flags;
/* size of message in words excluding header */
u32 sizew;
};
};
/* mbox message */
struct octep_ctrl_mbox_msg {
/* mbox transaction header */
union octep_ctrl_mbox_msg_hdr hdr;
/* pointer to message buffer */
void *msg;
};
/* Mbox queue */
struct octep_ctrl_mbox_q {
/* q element size, should be aligned to unsigned long */
u16 elem_sz;
/* q element count, should be power of 2 */
u16 elem_cnt;
/* q mask */
u16 mask;
/* producer address in bar mem */
u8 __iomem *hw_prod;
/* consumer address in bar mem */
u8 __iomem *hw_cons;
/* q base address in bar mem */
u8 __iomem *hw_q;
};
struct octep_ctrl_mbox {
/* host driver version */
u64 version;
/* size of bar memory */
u32 barmem_sz;
/* pointer to BAR memory */
u8 __iomem *barmem;
/* user context for callback, can be null */
void *user_ctx;
/* callback handler for processing request, called from octep_ctrl_mbox_recv */
int (*process_req)(void *user_ctx, struct octep_ctrl_mbox_msg *msg);
/* host-to-fw queue */
struct octep_ctrl_mbox_q h2fq;
/* fw-to-host queue */
struct octep_ctrl_mbox_q f2hq;
/* lock for h2fq */
struct mutex h2fq_lock;
/* lock for f2hq */
struct mutex f2hq_lock;
};
/* Initialize control mbox.
*
* @param mbox: non-null pointer to struct octep_ctrl_mbox.
*
* return value: 0 on success, -errno on failure.
*/
int octep_ctrl_mbox_init(struct octep_ctrl_mbox *mbox);
/* Send mbox message.
*
* @param mbox: non-null pointer to struct octep_ctrl_mbox.
*
* return value: 0 on success, -errno on failure.
*/
int octep_ctrl_mbox_send(struct octep_ctrl_mbox *mbox, struct octep_ctrl_mbox_msg *msg);
/* Retrieve mbox message.
*
* @param mbox: non-null pointer to struct octep_ctrl_mbox.
*
* return value: 0 on success, -errno on failure.
*/
int octep_ctrl_mbox_recv(struct octep_ctrl_mbox *mbox, struct octep_ctrl_mbox_msg *msg);
/* Uninitialize control mbox.
*
* @param ep: non-null pointer to struct octep_ctrl_mbox.
*
* return value: 0 on success, -errno on failure.
*/
int octep_ctrl_mbox_uninit(struct octep_ctrl_mbox *mbox);
#endif /* __OCTEP_CTRL_MBOX_H__ */
// SPDX-License-Identifier: GPL-2.0
/* Marvell Octeon EP (EndPoint) Ethernet Driver
*
* Copyright (C) 2020 Marvell.
*
*/
#include <linux/string.h>
#include <linux/types.h>
#include <linux/etherdevice.h>
#include <linux/pci.h>
#include "octep_config.h"
#include "octep_main.h"
#include "octep_ctrl_net.h"
int octep_get_link_status(struct octep_device *oct)
{
struct octep_ctrl_net_h2f_req req = {};
struct octep_ctrl_net_h2f_resp *resp;
struct octep_ctrl_mbox_msg msg = {};
int err;
req.hdr.cmd = OCTEP_CTRL_NET_H2F_CMD_LINK_STATUS;
req.link.cmd = OCTEP_CTRL_NET_CMD_GET;
msg.hdr.flags = OCTEP_CTRL_MBOX_MSG_HDR_FLAG_REQ;
msg.hdr.sizew = OCTEP_CTRL_NET_H2F_STATE_REQ_SZW;
msg.msg = &req;
err = octep_ctrl_mbox_send(&oct->ctrl_mbox, &msg);
if (err)
return err;
resp = (struct octep_ctrl_net_h2f_resp *)&req;
return resp->link.state;
}
void octep_set_link_status(struct octep_device *oct, bool up)
{
struct octep_ctrl_net_h2f_req req = {};
struct octep_ctrl_mbox_msg msg = {};
req.hdr.cmd = OCTEP_CTRL_NET_H2F_CMD_LINK_STATUS;
req.link.cmd = OCTEP_CTRL_NET_CMD_SET;
req.link.state = (up) ? OCTEP_CTRL_NET_STATE_UP : OCTEP_CTRL_NET_STATE_DOWN;
msg.hdr.flags = OCTEP_CTRL_MBOX_MSG_HDR_FLAG_REQ;
msg.hdr.sizew = OCTEP_CTRL_NET_H2F_STATE_REQ_SZW;
msg.msg = &req;
octep_ctrl_mbox_send(&oct->ctrl_mbox, &msg);
}
void octep_set_rx_state(struct octep_device *oct, bool up)
{
struct octep_ctrl_net_h2f_req req = {};
struct octep_ctrl_mbox_msg msg = {};
req.hdr.cmd = OCTEP_CTRL_NET_H2F_CMD_RX_STATE;
req.link.cmd = OCTEP_CTRL_NET_CMD_SET;
req.link.state = (up) ? OCTEP_CTRL_NET_STATE_UP : OCTEP_CTRL_NET_STATE_DOWN;
msg.hdr.flags = OCTEP_CTRL_MBOX_MSG_HDR_FLAG_REQ;
msg.hdr.sizew = OCTEP_CTRL_NET_H2F_STATE_REQ_SZW;
msg.msg = &req;
octep_ctrl_mbox_send(&oct->ctrl_mbox, &msg);
}
int octep_get_mac_addr(struct octep_device *oct, u8 *addr)
{
struct octep_ctrl_net_h2f_req req = {};
struct octep_ctrl_net_h2f_resp *resp;
struct octep_ctrl_mbox_msg msg = {};
int err;
req.hdr.cmd = OCTEP_CTRL_NET_H2F_CMD_MAC;
req.link.cmd = OCTEP_CTRL_NET_CMD_GET;
msg.hdr.flags = OCTEP_CTRL_MBOX_MSG_HDR_FLAG_REQ;
msg.hdr.sizew = OCTEP_CTRL_NET_H2F_MAC_REQ_SZW;
msg.msg = &req;
err = octep_ctrl_mbox_send(&oct->ctrl_mbox, &msg);
if (err)
return err;
resp = (struct octep_ctrl_net_h2f_resp *)&req;
memcpy(addr, resp->mac.addr, ETH_ALEN);
return err;
}
int octep_set_mac_addr(struct octep_device *oct, u8 *addr)
{
struct octep_ctrl_net_h2f_req req = {};
struct octep_ctrl_mbox_msg msg = {};
req.hdr.cmd = OCTEP_CTRL_NET_H2F_CMD_MAC;
req.mac.cmd = OCTEP_CTRL_NET_CMD_SET;
memcpy(&req.mac.addr, addr, ETH_ALEN);
msg.hdr.flags = OCTEP_CTRL_MBOX_MSG_HDR_FLAG_REQ;
msg.hdr.sizew = OCTEP_CTRL_NET_H2F_MAC_REQ_SZW;
msg.msg = &req;
return octep_ctrl_mbox_send(&oct->ctrl_mbox, &msg);
}
int octep_set_mtu(struct octep_device *oct, int mtu)
{
struct octep_ctrl_net_h2f_req req = {};
struct octep_ctrl_mbox_msg msg = {};
req.hdr.cmd = OCTEP_CTRL_NET_H2F_CMD_MTU;
req.mtu.cmd = OCTEP_CTRL_NET_CMD_SET;
req.mtu.val = mtu;
msg.hdr.flags = OCTEP_CTRL_MBOX_MSG_HDR_FLAG_REQ;
msg.hdr.sizew = OCTEP_CTRL_NET_H2F_MTU_REQ_SZW;
msg.msg = &req;
return octep_ctrl_mbox_send(&oct->ctrl_mbox, &msg);
}
int octep_get_if_stats(struct octep_device *oct)
{
void __iomem *iface_rx_stats;
void __iomem *iface_tx_stats;
struct octep_ctrl_net_h2f_req req = {};
struct octep_ctrl_mbox_msg msg = {};
int err;
req.hdr.cmd = OCTEP_CTRL_NET_H2F_CMD_GET_IF_STATS;
req.mac.cmd = OCTEP_CTRL_NET_CMD_GET;
req.get_stats.offset = oct->ctrl_mbox_ifstats_offset;
msg.hdr.flags = OCTEP_CTRL_MBOX_MSG_HDR_FLAG_REQ;
msg.hdr.sizew = OCTEP_CTRL_NET_H2F_GET_STATS_REQ_SZW;
msg.msg = &req;
err = octep_ctrl_mbox_send(&oct->ctrl_mbox, &msg);
if (err)
return err;
iface_rx_stats = oct->ctrl_mbox.barmem + oct->ctrl_mbox_ifstats_offset;
iface_tx_stats = oct->ctrl_mbox.barmem + oct->ctrl_mbox_ifstats_offset +
sizeof(struct octep_iface_rx_stats);
memcpy_fromio(&oct->iface_rx_stats, iface_rx_stats, sizeof(struct octep_iface_rx_stats));
memcpy_fromio(&oct->iface_tx_stats, iface_tx_stats, sizeof(struct octep_iface_tx_stats));
return err;
}
int octep_get_link_info(struct octep_device *oct)
{
struct octep_ctrl_net_h2f_req req = {};
struct octep_ctrl_net_h2f_resp *resp;
struct octep_ctrl_mbox_msg msg = {};
int err;
req.hdr.cmd = OCTEP_CTRL_NET_H2F_CMD_LINK_INFO;
req.mac.cmd = OCTEP_CTRL_NET_CMD_GET;
msg.hdr.flags = OCTEP_CTRL_MBOX_MSG_HDR_FLAG_REQ;
msg.hdr.sizew = OCTEP_CTRL_NET_H2F_LINK_INFO_REQ_SZW;
msg.msg = &req;
err = octep_ctrl_mbox_send(&oct->ctrl_mbox, &msg);
if (err)
return err;
resp = (struct octep_ctrl_net_h2f_resp *)&req;
oct->link_info.supported_modes = resp->link_info.supported_modes;
oct->link_info.advertised_modes = resp->link_info.advertised_modes;
oct->link_info.autoneg = resp->link_info.autoneg;
oct->link_info.pause = resp->link_info.pause;
oct->link_info.speed = resp->link_info.speed;
return err;
}
int octep_set_link_info(struct octep_device *oct, struct octep_iface_link_info *link_info)
{
struct octep_ctrl_net_h2f_req req = {};
struct octep_ctrl_mbox_msg msg = {};
req.hdr.cmd = OCTEP_CTRL_NET_H2F_CMD_LINK_INFO;
req.link_info.cmd = OCTEP_CTRL_NET_CMD_SET;
req.link_info.info.advertised_modes = link_info->advertised_modes;
req.link_info.info.autoneg = link_info->autoneg;
req.link_info.info.pause = link_info->pause;
req.link_info.info.speed = link_info->speed;
msg.hdr.flags = OCTEP_CTRL_MBOX_MSG_HDR_FLAG_REQ;
msg.hdr.sizew = OCTEP_CTRL_NET_H2F_LINK_INFO_REQ_SZW;
msg.msg = &req;
return octep_ctrl_mbox_send(&oct->ctrl_mbox, &msg);
}
/* SPDX-License-Identifier: GPL-2.0 */
/* Marvell Octeon EP (EndPoint) Ethernet Driver
*
* Copyright (C) 2020 Marvell.
*
*/
#ifndef __OCTEP_CTRL_NET_H__
#define __OCTEP_CTRL_NET_H__
/* Supported commands */
enum octep_ctrl_net_cmd {
OCTEP_CTRL_NET_CMD_GET = 0,
OCTEP_CTRL_NET_CMD_SET,
};
/* Supported states */
enum octep_ctrl_net_state {
OCTEP_CTRL_NET_STATE_DOWN = 0,
OCTEP_CTRL_NET_STATE_UP,
};
/* Supported replies */
enum octep_ctrl_net_reply {
OCTEP_CTRL_NET_REPLY_OK = 0,
OCTEP_CTRL_NET_REPLY_GENERIC_FAIL,
OCTEP_CTRL_NET_REPLY_INVALID_PARAM,
};
/* Supported host to fw commands */
enum octep_ctrl_net_h2f_cmd {
OCTEP_CTRL_NET_H2F_CMD_INVALID = 0,
OCTEP_CTRL_NET_H2F_CMD_MTU,
OCTEP_CTRL_NET_H2F_CMD_MAC,
OCTEP_CTRL_NET_H2F_CMD_GET_IF_STATS,
OCTEP_CTRL_NET_H2F_CMD_GET_XSTATS,
OCTEP_CTRL_NET_H2F_CMD_GET_Q_STATS,
OCTEP_CTRL_NET_H2F_CMD_LINK_STATUS,
OCTEP_CTRL_NET_H2F_CMD_RX_STATE,
OCTEP_CTRL_NET_H2F_CMD_LINK_INFO,
};
/* Supported fw to host commands */
enum octep_ctrl_net_f2h_cmd {
OCTEP_CTRL_NET_F2H_CMD_INVALID = 0,
OCTEP_CTRL_NET_F2H_CMD_LINK_STATUS,
};
struct octep_ctrl_net_req_hdr {
/* sender id */
u16 sender;
/* receiver id */
u16 receiver;
/* octep_ctrl_net_h2t_cmd */
u16 cmd;
/* reserved */
u16 rsvd0;
};
/* get/set mtu request */
struct octep_ctrl_net_h2f_req_cmd_mtu {
/* enum octep_ctrl_net_cmd */
u16 cmd;
/* 0-65535 */
u16 val;
};
/* get/set mac request */
struct octep_ctrl_net_h2f_req_cmd_mac {
/* enum octep_ctrl_net_cmd */
u16 cmd;
/* xx:xx:xx:xx:xx:xx */
u8 addr[ETH_ALEN];
};
/* get if_stats, xstats, q_stats request */
struct octep_ctrl_net_h2f_req_cmd_get_stats {
/* offset into barmem where fw should copy over stats */
u32 offset;
};
/* get/set link state, rx state */
struct octep_ctrl_net_h2f_req_cmd_state {
/* enum octep_ctrl_net_cmd */
u16 cmd;
/* enum octep_ctrl_net_state */
u16 state;
};
/* link info */
struct octep_ctrl_net_link_info {
/* Bitmap of Supported link speeds/modes */
u64 supported_modes;
/* Bitmap of Advertised link speeds/modes */
u64 advertised_modes;
/* Autonegotation state; bit 0=disabled; bit 1=enabled */
u8 autoneg;
/* Pause frames setting. bit 0=disabled; bit 1=enabled */
u8 pause;
/* Negotiated link speed in Mbps */
u32 speed;
};
/* get/set link info */
struct octep_ctrl_net_h2f_req_cmd_link_info {
/* enum octep_ctrl_net_cmd */
u16 cmd;
/* struct octep_ctrl_net_link_info */
struct octep_ctrl_net_link_info info;
};
/* Host to fw request data */
struct octep_ctrl_net_h2f_req {
struct octep_ctrl_net_req_hdr hdr;
union {
struct octep_ctrl_net_h2f_req_cmd_mtu mtu;
struct octep_ctrl_net_h2f_req_cmd_mac mac;
struct octep_ctrl_net_h2f_req_cmd_get_stats get_stats;
struct octep_ctrl_net_h2f_req_cmd_state link;
struct octep_ctrl_net_h2f_req_cmd_state rx;
struct octep_ctrl_net_h2f_req_cmd_link_info link_info;
};
} __packed;
struct octep_ctrl_net_resp_hdr {
/* sender id */
u16 sender;
/* receiver id */
u16 receiver;
/* octep_ctrl_net_h2t_cmd */
u16 cmd;
/* octep_ctrl_net_reply */
u16 reply;
};
/* get mtu response */
struct octep_ctrl_net_h2f_resp_cmd_mtu {
/* 0-65535 */
u16 val;
};
/* get mac response */
struct octep_ctrl_net_h2f_resp_cmd_mac {
/* xx:xx:xx:xx:xx:xx */
u8 addr[ETH_ALEN];
};
/* get link state, rx state response */
struct octep_ctrl_net_h2f_resp_cmd_state {
/* enum octep_ctrl_net_state */
u16 state;
};
/* Host to fw response data */
struct octep_ctrl_net_h2f_resp {
struct octep_ctrl_net_resp_hdr hdr;
union {
struct octep_ctrl_net_h2f_resp_cmd_mtu mtu;
struct octep_ctrl_net_h2f_resp_cmd_mac mac;
struct octep_ctrl_net_h2f_resp_cmd_state link;
struct octep_ctrl_net_h2f_resp_cmd_state rx;
struct octep_ctrl_net_link_info link_info;
};
} __packed;
/* link state notofication */
struct octep_ctrl_net_f2h_req_cmd_state {
/* enum octep_ctrl_net_state */
u16 state;
};
/* Fw to host request data */
struct octep_ctrl_net_f2h_req {
struct octep_ctrl_net_req_hdr hdr;
union {
struct octep_ctrl_net_f2h_req_cmd_state link;
};
};
/* Fw to host response data */
struct octep_ctrl_net_f2h_resp {
struct octep_ctrl_net_resp_hdr hdr;
};
/* Size of host to fw octep_ctrl_mbox queue element */
union octep_ctrl_net_h2f_data_sz {
struct octep_ctrl_net_h2f_req h2f_req;
struct octep_ctrl_net_h2f_resp h2f_resp;
};
/* Size of fw to host octep_ctrl_mbox queue element */
union octep_ctrl_net_f2h_data_sz {
struct octep_ctrl_net_f2h_req f2h_req;
struct octep_ctrl_net_f2h_resp f2h_resp;
};
/* size of host to fw data in words */
#define OCTEP_CTRL_NET_H2F_DATA_SZW ((sizeof(union octep_ctrl_net_h2f_data_sz)) / \
(sizeof(unsigned long)))
/* size of fw to host data in words */
#define OCTEP_CTRL_NET_F2H_DATA_SZW ((sizeof(union octep_ctrl_net_f2h_data_sz)) / \
(sizeof(unsigned long)))
/* size in words of get/set mtu request */
#define OCTEP_CTRL_NET_H2F_MTU_REQ_SZW 2
/* size in words of get/set mac request */
#define OCTEP_CTRL_NET_H2F_MAC_REQ_SZW 2
/* size in words of get stats request */
#define OCTEP_CTRL_NET_H2F_GET_STATS_REQ_SZW 2
/* size in words of get/set state request */
#define OCTEP_CTRL_NET_H2F_STATE_REQ_SZW 2
/* size in words of get/set link info request */
#define OCTEP_CTRL_NET_H2F_LINK_INFO_REQ_SZW 4
/* size in words of get mtu response */
#define OCTEP_CTRL_NET_H2F_GET_MTU_RESP_SZW 2
/* size in words of set mtu response */
#define OCTEP_CTRL_NET_H2F_SET_MTU_RESP_SZW 1
/* size in words of get mac response */
#define OCTEP_CTRL_NET_H2F_GET_MAC_RESP_SZW 2
/* size in words of set mac response */
#define OCTEP_CTRL_NET_H2F_SET_MAC_RESP_SZW 1
/* size in words of get state request */
#define OCTEP_CTRL_NET_H2F_GET_STATE_RESP_SZW 2
/* size in words of set state request */
#define OCTEP_CTRL_NET_H2F_SET_STATE_RESP_SZW 1
/* size in words of get link info request */
#define OCTEP_CTRL_NET_H2F_GET_LINK_INFO_RESP_SZW 4
/* size in words of set link info request */
#define OCTEP_CTRL_NET_H2F_SET_LINK_INFO_RESP_SZW 1
/** Get link status from firmware.
*
* @param oct: non-null pointer to struct octep_device.
*
* return value: link status 0=down, 1=up.
*/
int octep_get_link_status(struct octep_device *oct);
/** Set link status in firmware.
*
* @param oct: non-null pointer to struct octep_device.
* @param up: boolean status.
*/
void octep_set_link_status(struct octep_device *oct, bool up);
/** Set rx state in firmware.
*
* @param oct: non-null pointer to struct octep_device.
* @param up: boolean status.
*/
void octep_set_rx_state(struct octep_device *oct, bool up);
/** Get mac address from firmware.
*
* @param oct: non-null pointer to struct octep_device.
* @param addr: non-null pointer to mac address.
*
* return value: 0 on success, -errno on failure.
*/
int octep_get_mac_addr(struct octep_device *oct, u8 *addr);
/** Set mac address in firmware.
*
* @param oct: non-null pointer to struct octep_device.
* @param addr: non-null pointer to mac address.
*/
int octep_set_mac_addr(struct octep_device *oct, u8 *addr);
/** Set mtu in firmware.
*
* @param oct: non-null pointer to struct octep_device.
* @param mtu: mtu.
*/
int octep_set_mtu(struct octep_device *oct, int mtu);
/** Get interface statistics from firmware.
*
* @param oct: non-null pointer to struct octep_device.
*
* return value: 0 on success, -errno on failure.
*/
int octep_get_if_stats(struct octep_device *oct);
/** Get link info from firmware.
*
* @param oct: non-null pointer to struct octep_device.
*
* return value: 0 on success, -errno on failure.
*/
int octep_get_link_info(struct octep_device *oct);
/** Set link info in firmware.
*
* @param oct: non-null pointer to struct octep_device.
*/
int octep_set_link_info(struct octep_device *oct, struct octep_iface_link_info *link_info);
#endif /* __OCTEP_CTRL_NET_H__ */
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment