162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Linux network driver for QLogic BR-series Converged Network Adapter.
462306a36Sopenharmony_ci */
562306a36Sopenharmony_ci/*
662306a36Sopenharmony_ci * Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
762306a36Sopenharmony_ci * Copyright (c) 2014-2015 QLogic Corporation
862306a36Sopenharmony_ci * All rights reserved
962306a36Sopenharmony_ci * www.qlogic.com
1062306a36Sopenharmony_ci */
1162306a36Sopenharmony_ci
1262306a36Sopenharmony_ci#include "bfa_cee.h"
1362306a36Sopenharmony_ci#include "bfi_cna.h"
1462306a36Sopenharmony_ci#include "bfa_ioc.h"
1562306a36Sopenharmony_ci
1662306a36Sopenharmony_cistatic void bfa_cee_format_lldp_cfg(struct bfa_cee_lldp_cfg *lldp_cfg);
1762306a36Sopenharmony_cistatic void bfa_cee_format_cee_cfg(void *buffer);
1862306a36Sopenharmony_ci
1962306a36Sopenharmony_cistatic void
2062306a36Sopenharmony_cibfa_cee_format_cee_cfg(void *buffer)
2162306a36Sopenharmony_ci{
2262306a36Sopenharmony_ci	struct bfa_cee_attr *cee_cfg = buffer;
2362306a36Sopenharmony_ci	bfa_cee_format_lldp_cfg(&cee_cfg->lldp_remote);
2462306a36Sopenharmony_ci}
2562306a36Sopenharmony_ci
2662306a36Sopenharmony_cistatic void
2762306a36Sopenharmony_cibfa_cee_stats_swap(struct bfa_cee_stats *stats)
2862306a36Sopenharmony_ci{
2962306a36Sopenharmony_ci	u32 *buffer = (u32 *)stats;
3062306a36Sopenharmony_ci	int i;
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_ci	for (i = 0; i < (sizeof(struct bfa_cee_stats) / sizeof(u32));
3362306a36Sopenharmony_ci		i++) {
3462306a36Sopenharmony_ci		buffer[i] = ntohl(buffer[i]);
3562306a36Sopenharmony_ci	}
3662306a36Sopenharmony_ci}
3762306a36Sopenharmony_ci
3862306a36Sopenharmony_cistatic void
3962306a36Sopenharmony_cibfa_cee_format_lldp_cfg(struct bfa_cee_lldp_cfg *lldp_cfg)
4062306a36Sopenharmony_ci{
4162306a36Sopenharmony_ci	lldp_cfg->time_to_live =
4262306a36Sopenharmony_ci			ntohs(lldp_cfg->time_to_live);
4362306a36Sopenharmony_ci	lldp_cfg->enabled_system_cap =
4462306a36Sopenharmony_ci			ntohs(lldp_cfg->enabled_system_cap);
4562306a36Sopenharmony_ci}
4662306a36Sopenharmony_ci
4762306a36Sopenharmony_ci/**
4862306a36Sopenharmony_ci * bfa_cee_attr_meminfo - Returns the size of the DMA memory needed by CEE attributes
4962306a36Sopenharmony_ci */
5062306a36Sopenharmony_cistatic u32
5162306a36Sopenharmony_cibfa_cee_attr_meminfo(void)
5262306a36Sopenharmony_ci{
5362306a36Sopenharmony_ci	return roundup(sizeof(struct bfa_cee_attr), BFA_DMA_ALIGN_SZ);
5462306a36Sopenharmony_ci}
5562306a36Sopenharmony_ci/**
5662306a36Sopenharmony_ci * bfa_cee_stats_meminfo - Returns the size of the DMA memory needed by CEE stats
5762306a36Sopenharmony_ci */
5862306a36Sopenharmony_cistatic u32
5962306a36Sopenharmony_cibfa_cee_stats_meminfo(void)
6062306a36Sopenharmony_ci{
6162306a36Sopenharmony_ci	return roundup(sizeof(struct bfa_cee_stats), BFA_DMA_ALIGN_SZ);
6262306a36Sopenharmony_ci}
6362306a36Sopenharmony_ci
6462306a36Sopenharmony_ci/**
6562306a36Sopenharmony_ci * bfa_cee_get_attr_isr - CEE ISR for get-attributes responses from f/w
6662306a36Sopenharmony_ci *
6762306a36Sopenharmony_ci * @cee: Pointer to the CEE module
6862306a36Sopenharmony_ci * @status: Return status from the f/w
6962306a36Sopenharmony_ci */
7062306a36Sopenharmony_cistatic void
7162306a36Sopenharmony_cibfa_cee_get_attr_isr(struct bfa_cee *cee, enum bfa_status status)
7262306a36Sopenharmony_ci{
7362306a36Sopenharmony_ci	cee->get_attr_status = status;
7462306a36Sopenharmony_ci	if (status == BFA_STATUS_OK) {
7562306a36Sopenharmony_ci		memcpy(cee->attr, cee->attr_dma.kva,
7662306a36Sopenharmony_ci		    sizeof(struct bfa_cee_attr));
7762306a36Sopenharmony_ci		bfa_cee_format_cee_cfg(cee->attr);
7862306a36Sopenharmony_ci	}
7962306a36Sopenharmony_ci	cee->get_attr_pending = false;
8062306a36Sopenharmony_ci	if (cee->cbfn.get_attr_cbfn)
8162306a36Sopenharmony_ci		cee->cbfn.get_attr_cbfn(cee->cbfn.get_attr_cbarg, status);
8262306a36Sopenharmony_ci}
8362306a36Sopenharmony_ci
8462306a36Sopenharmony_ci/**
8562306a36Sopenharmony_ci * bfa_cee_get_stats_isr - CEE ISR for get-stats responses from f/w
8662306a36Sopenharmony_ci *
8762306a36Sopenharmony_ci * @cee: Pointer to the CEE module
8862306a36Sopenharmony_ci * @status: Return status from the f/w
8962306a36Sopenharmony_ci */
9062306a36Sopenharmony_cistatic void
9162306a36Sopenharmony_cibfa_cee_get_stats_isr(struct bfa_cee *cee, enum bfa_status status)
9262306a36Sopenharmony_ci{
9362306a36Sopenharmony_ci	cee->get_stats_status = status;
9462306a36Sopenharmony_ci	if (status == BFA_STATUS_OK) {
9562306a36Sopenharmony_ci		memcpy(cee->stats, cee->stats_dma.kva,
9662306a36Sopenharmony_ci			sizeof(struct bfa_cee_stats));
9762306a36Sopenharmony_ci		bfa_cee_stats_swap(cee->stats);
9862306a36Sopenharmony_ci	}
9962306a36Sopenharmony_ci	cee->get_stats_pending = false;
10062306a36Sopenharmony_ci	if (cee->cbfn.get_stats_cbfn)
10162306a36Sopenharmony_ci		cee->cbfn.get_stats_cbfn(cee->cbfn.get_stats_cbarg, status);
10262306a36Sopenharmony_ci}
10362306a36Sopenharmony_ci
10462306a36Sopenharmony_ci/**
10562306a36Sopenharmony_ci * bfa_cee_reset_stats_isr - CEE ISR for reset-stats responses from f/w
10662306a36Sopenharmony_ci *
10762306a36Sopenharmony_ci * @cee: Input Pointer to the CEE module
10862306a36Sopenharmony_ci * @status: Return status from the f/w
10962306a36Sopenharmony_ci */
11062306a36Sopenharmony_cistatic void
11162306a36Sopenharmony_cibfa_cee_reset_stats_isr(struct bfa_cee *cee, enum bfa_status status)
11262306a36Sopenharmony_ci{
11362306a36Sopenharmony_ci	cee->reset_stats_status = status;
11462306a36Sopenharmony_ci	cee->reset_stats_pending = false;
11562306a36Sopenharmony_ci	if (cee->cbfn.reset_stats_cbfn)
11662306a36Sopenharmony_ci		cee->cbfn.reset_stats_cbfn(cee->cbfn.reset_stats_cbarg, status);
11762306a36Sopenharmony_ci}
11862306a36Sopenharmony_ci/**
11962306a36Sopenharmony_ci * bfa_nw_cee_meminfo - Returns the size of the DMA memory needed by CEE module
12062306a36Sopenharmony_ci */
12162306a36Sopenharmony_ciu32
12262306a36Sopenharmony_cibfa_nw_cee_meminfo(void)
12362306a36Sopenharmony_ci{
12462306a36Sopenharmony_ci	return bfa_cee_attr_meminfo() + bfa_cee_stats_meminfo();
12562306a36Sopenharmony_ci}
12662306a36Sopenharmony_ci
12762306a36Sopenharmony_ci/**
12862306a36Sopenharmony_ci * bfa_nw_cee_mem_claim - Initialized CEE DMA Memory
12962306a36Sopenharmony_ci *
13062306a36Sopenharmony_ci * @cee: CEE module pointer
13162306a36Sopenharmony_ci * @dma_kva: Kernel Virtual Address of CEE DMA Memory
13262306a36Sopenharmony_ci * @dma_pa:  Physical Address of CEE DMA Memory
13362306a36Sopenharmony_ci */
13462306a36Sopenharmony_civoid
13562306a36Sopenharmony_cibfa_nw_cee_mem_claim(struct bfa_cee *cee, u8 *dma_kva, u64 dma_pa)
13662306a36Sopenharmony_ci{
13762306a36Sopenharmony_ci	cee->attr_dma.kva = dma_kva;
13862306a36Sopenharmony_ci	cee->attr_dma.pa = dma_pa;
13962306a36Sopenharmony_ci	cee->stats_dma.kva = dma_kva + bfa_cee_attr_meminfo();
14062306a36Sopenharmony_ci	cee->stats_dma.pa = dma_pa + bfa_cee_attr_meminfo();
14162306a36Sopenharmony_ci	cee->attr = (struct bfa_cee_attr *) dma_kva;
14262306a36Sopenharmony_ci	cee->stats = (struct bfa_cee_stats *)
14362306a36Sopenharmony_ci		(dma_kva + bfa_cee_attr_meminfo());
14462306a36Sopenharmony_ci}
14562306a36Sopenharmony_ci
14662306a36Sopenharmony_ci/**
14762306a36Sopenharmony_ci * bfa_nw_cee_get_attr - Send the request to the f/w to fetch CEE attributes.
14862306a36Sopenharmony_ci *
14962306a36Sopenharmony_ci * @cee: Pointer to the CEE module data structure.
15062306a36Sopenharmony_ci * @attr: attribute requested
15162306a36Sopenharmony_ci * @cbfn: function pointer
15262306a36Sopenharmony_ci * @cbarg: function pointer arguments
15362306a36Sopenharmony_ci *
15462306a36Sopenharmony_ci * Return: status
15562306a36Sopenharmony_ci */
15662306a36Sopenharmony_cienum bfa_status
15762306a36Sopenharmony_cibfa_nw_cee_get_attr(struct bfa_cee *cee, struct bfa_cee_attr *attr,
15862306a36Sopenharmony_ci		    bfa_cee_get_attr_cbfn_t cbfn, void *cbarg)
15962306a36Sopenharmony_ci{
16062306a36Sopenharmony_ci	struct bfi_cee_get_req *cmd;
16162306a36Sopenharmony_ci
16262306a36Sopenharmony_ci	BUG_ON(!((cee != NULL) && (cee->ioc != NULL)));
16362306a36Sopenharmony_ci	if (!bfa_nw_ioc_is_operational(cee->ioc))
16462306a36Sopenharmony_ci		return BFA_STATUS_IOC_FAILURE;
16562306a36Sopenharmony_ci
16662306a36Sopenharmony_ci	if (cee->get_attr_pending)
16762306a36Sopenharmony_ci		return  BFA_STATUS_DEVBUSY;
16862306a36Sopenharmony_ci
16962306a36Sopenharmony_ci	cee->get_attr_pending = true;
17062306a36Sopenharmony_ci	cmd = (struct bfi_cee_get_req *) cee->get_cfg_mb.msg;
17162306a36Sopenharmony_ci	cee->attr = attr;
17262306a36Sopenharmony_ci	cee->cbfn.get_attr_cbfn = cbfn;
17362306a36Sopenharmony_ci	cee->cbfn.get_attr_cbarg = cbarg;
17462306a36Sopenharmony_ci	bfi_h2i_set(cmd->mh, BFI_MC_CEE, BFI_CEE_H2I_GET_CFG_REQ,
17562306a36Sopenharmony_ci		    bfa_ioc_portid(cee->ioc));
17662306a36Sopenharmony_ci	bfa_dma_be_addr_set(cmd->dma_addr, cee->attr_dma.pa);
17762306a36Sopenharmony_ci	bfa_nw_ioc_mbox_queue(cee->ioc, &cee->get_cfg_mb, NULL, NULL);
17862306a36Sopenharmony_ci
17962306a36Sopenharmony_ci	return BFA_STATUS_OK;
18062306a36Sopenharmony_ci}
18162306a36Sopenharmony_ci
18262306a36Sopenharmony_ci/**
18362306a36Sopenharmony_ci * bfa_cee_isr - Handles Mail-box interrupts for CEE module.
18462306a36Sopenharmony_ci * @cbarg: argument passed containing pointer to the CEE module data structure.
18562306a36Sopenharmony_ci * @m: message pointer
18662306a36Sopenharmony_ci */
18762306a36Sopenharmony_ci
18862306a36Sopenharmony_cistatic void
18962306a36Sopenharmony_cibfa_cee_isr(void *cbarg, struct bfi_mbmsg *m)
19062306a36Sopenharmony_ci{
19162306a36Sopenharmony_ci	union bfi_cee_i2h_msg_u *msg;
19262306a36Sopenharmony_ci	struct bfi_cee_get_rsp *get_rsp;
19362306a36Sopenharmony_ci	struct bfa_cee *cee = (struct bfa_cee *) cbarg;
19462306a36Sopenharmony_ci	msg = (union bfi_cee_i2h_msg_u *) m;
19562306a36Sopenharmony_ci	get_rsp = (struct bfi_cee_get_rsp *) m;
19662306a36Sopenharmony_ci	switch (msg->mh.msg_id) {
19762306a36Sopenharmony_ci	case BFI_CEE_I2H_GET_CFG_RSP:
19862306a36Sopenharmony_ci		bfa_cee_get_attr_isr(cee, get_rsp->cmd_status);
19962306a36Sopenharmony_ci		break;
20062306a36Sopenharmony_ci	case BFI_CEE_I2H_GET_STATS_RSP:
20162306a36Sopenharmony_ci		bfa_cee_get_stats_isr(cee, get_rsp->cmd_status);
20262306a36Sopenharmony_ci		break;
20362306a36Sopenharmony_ci	case BFI_CEE_I2H_RESET_STATS_RSP:
20462306a36Sopenharmony_ci		bfa_cee_reset_stats_isr(cee, get_rsp->cmd_status);
20562306a36Sopenharmony_ci		break;
20662306a36Sopenharmony_ci	default:
20762306a36Sopenharmony_ci		BUG_ON(1);
20862306a36Sopenharmony_ci	}
20962306a36Sopenharmony_ci}
21062306a36Sopenharmony_ci
21162306a36Sopenharmony_ci/**
21262306a36Sopenharmony_ci * bfa_cee_notify - CEE module heart-beat failure handler.
21362306a36Sopenharmony_ci *
21462306a36Sopenharmony_ci * @arg: argument passed containing pointer to the CEE module data structure.
21562306a36Sopenharmony_ci * @event: IOC event type
21662306a36Sopenharmony_ci */
21762306a36Sopenharmony_ci
21862306a36Sopenharmony_cistatic void
21962306a36Sopenharmony_cibfa_cee_notify(void *arg, enum bfa_ioc_event event)
22062306a36Sopenharmony_ci{
22162306a36Sopenharmony_ci	struct bfa_cee *cee;
22262306a36Sopenharmony_ci	cee = (struct bfa_cee *) arg;
22362306a36Sopenharmony_ci
22462306a36Sopenharmony_ci	switch (event) {
22562306a36Sopenharmony_ci	case BFA_IOC_E_DISABLED:
22662306a36Sopenharmony_ci	case BFA_IOC_E_FAILED:
22762306a36Sopenharmony_ci		if (cee->get_attr_pending) {
22862306a36Sopenharmony_ci			cee->get_attr_status = BFA_STATUS_FAILED;
22962306a36Sopenharmony_ci			cee->get_attr_pending  = false;
23062306a36Sopenharmony_ci			if (cee->cbfn.get_attr_cbfn) {
23162306a36Sopenharmony_ci				cee->cbfn.get_attr_cbfn(
23262306a36Sopenharmony_ci					cee->cbfn.get_attr_cbarg,
23362306a36Sopenharmony_ci					BFA_STATUS_FAILED);
23462306a36Sopenharmony_ci			}
23562306a36Sopenharmony_ci		}
23662306a36Sopenharmony_ci		if (cee->get_stats_pending) {
23762306a36Sopenharmony_ci			cee->get_stats_status = BFA_STATUS_FAILED;
23862306a36Sopenharmony_ci			cee->get_stats_pending  = false;
23962306a36Sopenharmony_ci			if (cee->cbfn.get_stats_cbfn) {
24062306a36Sopenharmony_ci				cee->cbfn.get_stats_cbfn(
24162306a36Sopenharmony_ci					cee->cbfn.get_stats_cbarg,
24262306a36Sopenharmony_ci					BFA_STATUS_FAILED);
24362306a36Sopenharmony_ci			}
24462306a36Sopenharmony_ci		}
24562306a36Sopenharmony_ci		if (cee->reset_stats_pending) {
24662306a36Sopenharmony_ci			cee->reset_stats_status = BFA_STATUS_FAILED;
24762306a36Sopenharmony_ci			cee->reset_stats_pending  = false;
24862306a36Sopenharmony_ci			if (cee->cbfn.reset_stats_cbfn) {
24962306a36Sopenharmony_ci				cee->cbfn.reset_stats_cbfn(
25062306a36Sopenharmony_ci					cee->cbfn.reset_stats_cbarg,
25162306a36Sopenharmony_ci					BFA_STATUS_FAILED);
25262306a36Sopenharmony_ci			}
25362306a36Sopenharmony_ci		}
25462306a36Sopenharmony_ci		break;
25562306a36Sopenharmony_ci
25662306a36Sopenharmony_ci	default:
25762306a36Sopenharmony_ci		break;
25862306a36Sopenharmony_ci	}
25962306a36Sopenharmony_ci}
26062306a36Sopenharmony_ci
26162306a36Sopenharmony_ci/**
26262306a36Sopenharmony_ci * bfa_nw_cee_attach - CEE module-attach API
26362306a36Sopenharmony_ci *
26462306a36Sopenharmony_ci * @cee: Pointer to the CEE module data structure
26562306a36Sopenharmony_ci * @ioc: Pointer to the ioc module data structure
26662306a36Sopenharmony_ci * @dev: Pointer to the device driver module data structure.
26762306a36Sopenharmony_ci *       The device driver specific mbox ISR functions have
26862306a36Sopenharmony_ci *       this pointer as one of the parameters.
26962306a36Sopenharmony_ci */
27062306a36Sopenharmony_civoid
27162306a36Sopenharmony_cibfa_nw_cee_attach(struct bfa_cee *cee, struct bfa_ioc *ioc,
27262306a36Sopenharmony_ci		void *dev)
27362306a36Sopenharmony_ci{
27462306a36Sopenharmony_ci	BUG_ON(!(cee != NULL));
27562306a36Sopenharmony_ci	cee->dev = dev;
27662306a36Sopenharmony_ci	cee->ioc = ioc;
27762306a36Sopenharmony_ci
27862306a36Sopenharmony_ci	bfa_nw_ioc_mbox_regisr(cee->ioc, BFI_MC_CEE, bfa_cee_isr, cee);
27962306a36Sopenharmony_ci	bfa_ioc_notify_init(&cee->ioc_notify, bfa_cee_notify, cee);
28062306a36Sopenharmony_ci	bfa_nw_ioc_notify_register(cee->ioc, &cee->ioc_notify);
28162306a36Sopenharmony_ci}
282