Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit c4d06d2d authored by Aviad Krawczyk's avatar Aviad Krawczyk Committed by David S. Miller
Browse files

net-next/hinic: Add Rx mode and link event handler



Add port management message for setting Rx mode in the card,
used for rx_mode netdev operation.
The link event handler is used for getting a notification about the
link state.

Signed-off-by: default avatarAviad Krawczyk <aviad.krawczyk@huawei.com>
Signed-off-by: default avatarZhao Chen <zhaochen6@huawei.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 25a3ba61
Loading
Loading
Loading
Loading
+17 −0
Original line number Diff line number Diff line
@@ -19,19 +19,36 @@
#include <linux/netdevice.h>
#include <linux/types.h>
#include <linux/semaphore.h>
#include <linux/workqueue.h>
#include <linux/bitops.h>

#include "hinic_hw_dev.h"

#define HINIC_DRV_NAME          "hinic"

enum hinic_flags {
	HINIC_LINK_UP = BIT(0),
	HINIC_INTF_UP = BIT(1),
};

struct hinic_rx_mode_work {
	struct work_struct      work;
	u32                     rx_mode;
};

struct hinic_dev {
	struct net_device               *netdev;
	struct hinic_hwdev              *hwdev;

	u32                             msg_enable;

	unsigned int                    flags;

	struct semaphore                mgmt_lock;
	unsigned long                   *vlan_bitmap;

	struct hinic_rx_mode_work       rx_mode_work;
	struct workqueue_struct         *workq;
};

#endif
+2 −0
Original line number Diff line number Diff line
@@ -20,6 +20,8 @@
#define HINIC_CSR_FUNC_ATTR0_ADDR                       0x0
#define HINIC_CSR_FUNC_ATTR1_ADDR                       0x4

#define HINIC_CSR_FUNC_ATTR5_ADDR                       0x14

#define HINIC_DMA_ATTR_BASE                             0xC80
#define HINIC_ELECTION_BASE                             0x4200

+122 −0
Original line number Diff line number Diff line
@@ -229,6 +229,118 @@ int hinic_port_msg_cmd(struct hinic_hwdev *hwdev, enum hinic_port_cmd cmd,
				 HINIC_MGMT_MSG_SYNC);
}

/**
 * hinic_hwdev_cb_register - register callback handler for MGMT events
 * @hwdev: the NIC HW device
 * @cmd: the mgmt event
 * @handle: private data for the handler
 * @handler: event handler
 **/
void hinic_hwdev_cb_register(struct hinic_hwdev *hwdev,
			     enum hinic_mgmt_msg_cmd cmd, void *handle,
			     void (*handler)(void *handle, void *buf_in,
					     u16 in_size, void *buf_out,
					     u16 *out_size))
{
	struct hinic_hwif *hwif = hwdev->hwif;
	struct pci_dev *pdev = hwif->pdev;
	struct hinic_pfhwdev *pfhwdev;
	struct hinic_nic_cb *nic_cb;
	u8 cmd_cb;

	if (!HINIC_IS_PF(hwif) && !HINIC_IS_PPF(hwif)) {
		dev_err(&pdev->dev, "unsupported PCI Function type\n");
		return;
	}

	pfhwdev = container_of(hwdev, struct hinic_pfhwdev, hwdev);

	cmd_cb = cmd - HINIC_MGMT_MSG_CMD_BASE;
	nic_cb = &pfhwdev->nic_cb[cmd_cb];

	nic_cb->handler = handler;
	nic_cb->handle = handle;
	nic_cb->cb_state = HINIC_CB_ENABLED;
}

/**
 * hinic_hwdev_cb_unregister - unregister callback handler for MGMT events
 * @hwdev: the NIC HW device
 * @cmd: the mgmt event
 **/
void hinic_hwdev_cb_unregister(struct hinic_hwdev *hwdev,
			       enum hinic_mgmt_msg_cmd cmd)
{
	struct hinic_hwif *hwif = hwdev->hwif;
	struct pci_dev *pdev = hwif->pdev;
	struct hinic_pfhwdev *pfhwdev;
	struct hinic_nic_cb *nic_cb;
	u8 cmd_cb;

	if (!HINIC_IS_PF(hwif) && !HINIC_IS_PPF(hwif)) {
		dev_err(&pdev->dev, "unsupported PCI Function type\n");
		return;
	}

	pfhwdev = container_of(hwdev, struct hinic_pfhwdev, hwdev);

	cmd_cb = cmd - HINIC_MGMT_MSG_CMD_BASE;
	nic_cb = &pfhwdev->nic_cb[cmd_cb];

	nic_cb->cb_state &= ~HINIC_CB_ENABLED;

	while (nic_cb->cb_state & HINIC_CB_RUNNING)
		schedule();

	nic_cb->handler = NULL;
}

/**
 * nic_mgmt_msg_handler - nic mgmt event handler
 * @handle: private data for the handler
 * @buf_in: input buffer
 * @in_size: input size
 * @buf_out: output buffer
 * @out_size: returned output size
 **/
static void nic_mgmt_msg_handler(void *handle, u8 cmd, void *buf_in,
				 u16 in_size, void *buf_out, u16 *out_size)
{
	struct hinic_pfhwdev *pfhwdev = handle;
	enum hinic_cb_state cb_state;
	struct hinic_nic_cb *nic_cb;
	struct hinic_hwdev *hwdev;
	struct hinic_hwif *hwif;
	struct pci_dev *pdev;
	u8 cmd_cb;

	hwdev = &pfhwdev->hwdev;
	hwif = hwdev->hwif;
	pdev = hwif->pdev;

	if ((cmd < HINIC_MGMT_MSG_CMD_BASE) ||
	    (cmd >= HINIC_MGMT_MSG_CMD_MAX)) {
		dev_err(&pdev->dev, "unknown L2NIC event, cmd = %d\n", cmd);
		return;
	}

	cmd_cb = cmd - HINIC_MGMT_MSG_CMD_BASE;

	nic_cb = &pfhwdev->nic_cb[cmd_cb];

	cb_state = cmpxchg(&nic_cb->cb_state,
			   HINIC_CB_ENABLED,
			   HINIC_CB_ENABLED | HINIC_CB_RUNNING);

	if ((cb_state == HINIC_CB_ENABLED) && (nic_cb->handler))
		nic_cb->handler(nic_cb->handle, buf_in,
				in_size, buf_out, out_size);
	else
		dev_err(&pdev->dev, "Unhandled NIC Event %d\n", cmd);

	nic_cb->cb_state &= ~HINIC_CB_RUNNING;
}

/**
 * init_pfhwdev - Initialize the extended components of PF
 * @pfhwdev: the HW device for PF
@@ -248,6 +360,10 @@ static int init_pfhwdev(struct hinic_pfhwdev *pfhwdev)
		return err;
	}

	hinic_register_mgmt_msg_cb(&pfhwdev->pf_to_mgmt, HINIC_MOD_L2NIC,
				   pfhwdev, nic_mgmt_msg_handler);

	hinic_set_pf_action(hwif, HINIC_PF_MGMT_ACTIVE);
	return 0;
}

@@ -257,6 +373,12 @@ static int init_pfhwdev(struct hinic_pfhwdev *pfhwdev)
 **/
static void free_pfhwdev(struct hinic_pfhwdev *pfhwdev)
{
	struct hinic_hwdev *hwdev = &pfhwdev->hwdev;

	hinic_set_pf_action(hwdev->hwif, HINIC_PF_MGMT_INIT);

	hinic_unregister_mgmt_msg_cb(&pfhwdev->pf_to_mgmt, HINIC_MOD_L2NIC);

	hinic_pf_to_mgmt_free(&pfhwdev->pf_to_mgmt);
}

+37 −0
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@

#include <linux/pci.h>
#include <linux/types.h>
#include <linux/bitops.h>

#include "hinic_hw_if.h"
#include "hinic_hw_eqs.h"
@@ -25,6 +26,9 @@

#define HINIC_MAX_QPS   32

#define HINIC_MGMT_NUM_MSG_CMD  (HINIC_MGMT_MSG_CMD_MAX - \
				 HINIC_MGMT_MSG_CMD_BASE)

struct hinic_cap {
	u16     max_qps;
	u16     num_qps;
@@ -55,6 +59,19 @@ enum hinic_port_cmd {
	HINIC_PORT_CMD_GET_CAP          = 170,
};

enum hinic_mgmt_msg_cmd {
	HINIC_MGMT_MSG_CMD_BASE         = 160,

	HINIC_MGMT_MSG_CMD_LINK_STATUS  = 160,

	HINIC_MGMT_MSG_CMD_MAX,
};

enum hinic_cb_state {
	HINIC_CB_ENABLED = BIT(0),
	HINIC_CB_RUNNING = BIT(1),
};

struct hinic_hwdev {
	struct hinic_hwif               *hwif;
	struct msix_entry               *msix_entries;
@@ -64,12 +81,32 @@ struct hinic_hwdev {
	struct hinic_cap                nic_cap;
};

struct hinic_nic_cb {
	void    (*handler)(void *handle, void *buf_in,
			   u16 in_size, void *buf_out,
			   u16 *out_size);

	void            *handle;
	unsigned long   cb_state;
};

struct hinic_pfhwdev {
	struct hinic_hwdev              hwdev;

	struct hinic_pf_to_mgmt         pf_to_mgmt;

	struct hinic_nic_cb             nic_cb[HINIC_MGMT_NUM_MSG_CMD];
};

void hinic_hwdev_cb_register(struct hinic_hwdev *hwdev,
			     enum hinic_mgmt_msg_cmd cmd, void *handle,
			     void (*handler)(void *handle, void *buf_in,
					     u16 in_size, void *buf_out,
					     u16 *out_size));

void hinic_hwdev_cb_unregister(struct hinic_hwdev *hwdev,
			       enum hinic_mgmt_msg_cmd cmd);

int hinic_port_msg_cmd(struct hinic_hwdev *hwdev, enum hinic_port_cmd cmd,
		       void *buf_in, u16 in_size, void *buf_out,
		       u16 *out_size);
+17 −0
Original line number Diff line number Diff line
@@ -115,6 +115,23 @@ int hinic_msix_attr_cnt_clear(struct hinic_hwif *hwif, u16 msix_index)
	return 0;
}

/**
 * hinic_set_pf_action - set action on pf channel
 * @hwif: the HW interface of a pci function device
 * @action: action on pf channel
 *
 * Return 0 - Success, negative - Failure
 **/
void hinic_set_pf_action(struct hinic_hwif *hwif, enum hinic_pf_action action)
{
	u32 attr5 = hinic_hwif_read_reg(hwif, HINIC_CSR_FUNC_ATTR5_ADDR);

	attr5 = HINIC_FA5_CLEAR(attr5, PF_ACTION);
	attr5 |= HINIC_FA5_SET(action, PF_ACTION);

	hinic_hwif_write_reg(hwif, HINIC_CSR_FUNC_ATTR5_ADDR, attr5);
}

/**
 * hwif_ready - test if the HW is ready for use
 * @hwif: the HW interface of a pci function device
Loading