xref: /linux/drivers/infiniband/ulp/opa_vnic/opa_vnic_vema.c (revision 03ab8e6297acd1bc0eedaa050e2a1635c576fd11)
11bd671abSVishwanathapura, Niranjana /*
21bd671abSVishwanathapura, Niranjana  * Copyright(c) 2017 Intel Corporation.
3*4892298cSScott Breyer  * Copyright(c) 2021 Cornelis Networks.
41bd671abSVishwanathapura, Niranjana  *
51bd671abSVishwanathapura, Niranjana  * This file is provided under a dual BSD/GPLv2 license.  When using or
61bd671abSVishwanathapura, Niranjana  * redistributing this file, you may do so under either license.
71bd671abSVishwanathapura, Niranjana  *
81bd671abSVishwanathapura, Niranjana  * GPL LICENSE SUMMARY
91bd671abSVishwanathapura, Niranjana  *
101bd671abSVishwanathapura, Niranjana  * This program is free software; you can redistribute it and/or modify
111bd671abSVishwanathapura, Niranjana  * it under the terms of version 2 of the GNU General Public License as
121bd671abSVishwanathapura, Niranjana  * published by the Free Software Foundation.
131bd671abSVishwanathapura, Niranjana  *
141bd671abSVishwanathapura, Niranjana  * This program is distributed in the hope that it will be useful, but
151bd671abSVishwanathapura, Niranjana  * WITHOUT ANY WARRANTY; without even the implied warranty of
161bd671abSVishwanathapura, Niranjana  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
171bd671abSVishwanathapura, Niranjana  * General Public License for more details.
181bd671abSVishwanathapura, Niranjana  *
191bd671abSVishwanathapura, Niranjana  * BSD LICENSE
201bd671abSVishwanathapura, Niranjana  *
211bd671abSVishwanathapura, Niranjana  * Redistribution and use in source and binary forms, with or without
221bd671abSVishwanathapura, Niranjana  * modification, are permitted provided that the following conditions
231bd671abSVishwanathapura, Niranjana  * are met:
241bd671abSVishwanathapura, Niranjana  *
251bd671abSVishwanathapura, Niranjana  *  - Redistributions of source code must retain the above copyright
261bd671abSVishwanathapura, Niranjana  *    notice, this list of conditions and the following disclaimer.
271bd671abSVishwanathapura, Niranjana  *  - Redistributions in binary form must reproduce the above copyright
281bd671abSVishwanathapura, Niranjana  *    notice, this list of conditions and the following disclaimer in
291bd671abSVishwanathapura, Niranjana  *    the documentation and/or other materials provided with the
301bd671abSVishwanathapura, Niranjana  *    distribution.
311bd671abSVishwanathapura, Niranjana  *  - Neither the name of Intel Corporation nor the names of its
321bd671abSVishwanathapura, Niranjana  *    contributors may be used to endorse or promote products derived
331bd671abSVishwanathapura, Niranjana  *    from this software without specific prior written permission.
341bd671abSVishwanathapura, Niranjana  *
351bd671abSVishwanathapura, Niranjana  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
361bd671abSVishwanathapura, Niranjana  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
371bd671abSVishwanathapura, Niranjana  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
381bd671abSVishwanathapura, Niranjana  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
391bd671abSVishwanathapura, Niranjana  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
401bd671abSVishwanathapura, Niranjana  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
411bd671abSVishwanathapura, Niranjana  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
421bd671abSVishwanathapura, Niranjana  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
431bd671abSVishwanathapura, Niranjana  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
441bd671abSVishwanathapura, Niranjana  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
451bd671abSVishwanathapura, Niranjana  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
461bd671abSVishwanathapura, Niranjana  *
471bd671abSVishwanathapura, Niranjana  */
481bd671abSVishwanathapura, Niranjana 
491bd671abSVishwanathapura, Niranjana /*
50*4892298cSScott Breyer  * This file contains OPX Virtual Network Interface Controller (VNIC)
511bd671abSVishwanathapura, Niranjana  * Ethernet Management Agent (EMA) driver
521bd671abSVishwanathapura, Niranjana  */
531bd671abSVishwanathapura, Niranjana 
541bd671abSVishwanathapura, Niranjana #include <linux/module.h>
55fae7a699SMatthew Wilcox #include <linux/xarray.h>
561bd671abSVishwanathapura, Niranjana #include <rdma/ib_addr.h>
57cb49366fSVishwanathapura, Niranjana #include <rdma/ib_verbs.h>
58cb49366fSVishwanathapura, Niranjana #include <rdma/opa_smi.h>
59cb49366fSVishwanathapura, Niranjana #include <rdma/opa_port_info.h>
601bd671abSVishwanathapura, Niranjana 
611bd671abSVishwanathapura, Niranjana #include "opa_vnic_internal.h"
621bd671abSVishwanathapura, Niranjana 
631bd671abSVishwanathapura, Niranjana char opa_vnic_driver_name[] = "opa_vnic";
641bd671abSVishwanathapura, Niranjana 
651bd671abSVishwanathapura, Niranjana /*
661bd671abSVishwanathapura, Niranjana  * The trap service level is kept in bits 3 to 7 in the trap_sl_rsvd
671bd671abSVishwanathapura, Niranjana  * field in the class port info MAD.
681bd671abSVishwanathapura, Niranjana  */
691bd671abSVishwanathapura, Niranjana #define GET_TRAP_SL_FROM_CLASS_PORT_INFO(x)  (((x) >> 3) & 0x1f)
701bd671abSVishwanathapura, Niranjana 
711bd671abSVishwanathapura, Niranjana /* Cap trap bursts to a reasonable limit good for normal cases */
721bd671abSVishwanathapura, Niranjana #define OPA_VNIC_TRAP_BURST_LIMIT 4
731bd671abSVishwanathapura, Niranjana 
741bd671abSVishwanathapura, Niranjana /*
751bd671abSVishwanathapura, Niranjana  * VNIC trap limit timeout.
761bd671abSVishwanathapura, Niranjana  * Inverse of cap2_mask response time out (1.0737 secs) = 0.9
771bd671abSVishwanathapura, Niranjana  * secs approx IB spec 13.4.6.2.1 PortInfoSubnetTimeout and
781bd671abSVishwanathapura, Niranjana  * 13.4.9 Traps.
791bd671abSVishwanathapura, Niranjana  */
801bd671abSVishwanathapura, Niranjana #define OPA_VNIC_TRAP_TIMEOUT  ((4096 * (1UL << 18)) / 1000)
811bd671abSVishwanathapura, Niranjana 
821bd671abSVishwanathapura, Niranjana #define OPA_VNIC_UNSUP_ATTR  \
831bd671abSVishwanathapura, Niranjana 		cpu_to_be16(IB_MGMT_MAD_STATUS_UNSUPPORTED_METHOD_ATTRIB)
841bd671abSVishwanathapura, Niranjana 
851bd671abSVishwanathapura, Niranjana #define OPA_VNIC_INVAL_ATTR  \
861bd671abSVishwanathapura, Niranjana 		cpu_to_be16(IB_MGMT_MAD_STATUS_INVALID_ATTRIB_VALUE)
871bd671abSVishwanathapura, Niranjana 
881bd671abSVishwanathapura, Niranjana #define OPA_VNIC_CLASS_CAP_TRAP   0x1
891bd671abSVishwanathapura, Niranjana 
901bd671abSVishwanathapura, Niranjana /* Maximum number of VNIC ports supported */
911bd671abSVishwanathapura, Niranjana #define OPA_VNIC_MAX_NUM_VPORT    255
921bd671abSVishwanathapura, Niranjana 
931bd671abSVishwanathapura, Niranjana /**
941bd671abSVishwanathapura, Niranjana  * struct opa_vnic_vema_port -- VNIC VEMA port details
951bd671abSVishwanathapura, Niranjana  * @cport: pointer to port
961bd671abSVishwanathapura, Niranjana  * @mad_agent: pointer to mad agent for port
971bd671abSVishwanathapura, Niranjana  * @class_port_info: Class port info information.
981bd671abSVishwanathapura, Niranjana  * @tid: Transaction id
991bd671abSVishwanathapura, Niranjana  * @port_num: OPA port number
100fae7a699SMatthew Wilcox  * @vports: vnic ports
1011bd671abSVishwanathapura, Niranjana  * @event_handler: ib event handler
1021bd671abSVishwanathapura, Niranjana  * @lock: adapter interface lock
1031bd671abSVishwanathapura, Niranjana  */
1041bd671abSVishwanathapura, Niranjana struct opa_vnic_vema_port {
1051bd671abSVishwanathapura, Niranjana 	struct opa_vnic_ctrl_port      *cport;
1061bd671abSVishwanathapura, Niranjana 	struct ib_mad_agent            *mad_agent;
1071bd671abSVishwanathapura, Niranjana 	struct opa_class_port_info      class_port_info;
1081bd671abSVishwanathapura, Niranjana 	u64                             tid;
1091bd671abSVishwanathapura, Niranjana 	u8                              port_num;
110fae7a699SMatthew Wilcox 	struct xarray                   vports;
1111bd671abSVishwanathapura, Niranjana 	struct ib_event_handler         event_handler;
1121bd671abSVishwanathapura, Niranjana 
1131bd671abSVishwanathapura, Niranjana 	/* Lock to query/update network adapter */
1141bd671abSVishwanathapura, Niranjana 	struct mutex                    lock;
1151bd671abSVishwanathapura, Niranjana };
1161bd671abSVishwanathapura, Niranjana 
11711a0ae4cSJason Gunthorpe static int opa_vnic_vema_add_one(struct ib_device *device);
1181bd671abSVishwanathapura, Niranjana static void opa_vnic_vema_rem_one(struct ib_device *device,
1191bd671abSVishwanathapura, Niranjana 				  void *client_data);
1201bd671abSVishwanathapura, Niranjana 
1211bd671abSVishwanathapura, Niranjana static struct ib_client opa_vnic_client = {
1221bd671abSVishwanathapura, Niranjana 	.name   = opa_vnic_driver_name,
1231bd671abSVishwanathapura, Niranjana 	.add    = opa_vnic_vema_add_one,
1241bd671abSVishwanathapura, Niranjana 	.remove = opa_vnic_vema_rem_one,
1251bd671abSVishwanathapura, Niranjana };
1261bd671abSVishwanathapura, Niranjana 
1271bd671abSVishwanathapura, Niranjana /**
1281bd671abSVishwanathapura, Niranjana  * vema_get_vport_num -- Get the vnic from the mad
1291bd671abSVishwanathapura, Niranjana  * @recvd_mad:  Received mad
1301bd671abSVishwanathapura, Niranjana  *
1311bd671abSVishwanathapura, Niranjana  * Return: returns value of the vnic port number
1321bd671abSVishwanathapura, Niranjana  */
vema_get_vport_num(struct opa_vnic_vema_mad * recvd_mad)1331bd671abSVishwanathapura, Niranjana static inline u8 vema_get_vport_num(struct opa_vnic_vema_mad *recvd_mad)
1341bd671abSVishwanathapura, Niranjana {
1351bd671abSVishwanathapura, Niranjana 	return be32_to_cpu(recvd_mad->mad_hdr.attr_mod) & 0xff;
1361bd671abSVishwanathapura, Niranjana }
1371bd671abSVishwanathapura, Niranjana 
1381bd671abSVishwanathapura, Niranjana /**
1391bd671abSVishwanathapura, Niranjana  * vema_get_vport_adapter -- Get vnic port adapter from recvd mad
1401bd671abSVishwanathapura, Niranjana  * @recvd_mad: received mad
1411bd671abSVishwanathapura, Niranjana  * @port: ptr to port struct on which MAD was recvd
1421bd671abSVishwanathapura, Niranjana  *
1431bd671abSVishwanathapura, Niranjana  * Return: vnic adapter
1441bd671abSVishwanathapura, Niranjana  */
1451bd671abSVishwanathapura, Niranjana static inline struct opa_vnic_adapter *
vema_get_vport_adapter(struct opa_vnic_vema_mad * recvd_mad,struct opa_vnic_vema_port * port)1461bd671abSVishwanathapura, Niranjana vema_get_vport_adapter(struct opa_vnic_vema_mad *recvd_mad,
1471bd671abSVishwanathapura, Niranjana 		       struct opa_vnic_vema_port *port)
1481bd671abSVishwanathapura, Niranjana {
1491bd671abSVishwanathapura, Niranjana 	u8 vport_num = vema_get_vport_num(recvd_mad);
1501bd671abSVishwanathapura, Niranjana 
151fae7a699SMatthew Wilcox 	return xa_load(&port->vports, vport_num);
1521bd671abSVishwanathapura, Niranjana }
1531bd671abSVishwanathapura, Niranjana 
1541bd671abSVishwanathapura, Niranjana /**
1551bd671abSVishwanathapura, Niranjana  * vema_mac_tbl_req_ok -- Check if mac request has correct values
1561bd671abSVishwanathapura, Niranjana  * @mac_tbl: mac table
1571bd671abSVishwanathapura, Niranjana  *
1581bd671abSVishwanathapura, Niranjana  * This function checks for the validity of the offset and number of
1591bd671abSVishwanathapura, Niranjana  * entries required.
1601bd671abSVishwanathapura, Niranjana  *
1611bd671abSVishwanathapura, Niranjana  * Return: true if offset and num_entries are valid
1621bd671abSVishwanathapura, Niranjana  */
vema_mac_tbl_req_ok(struct opa_veswport_mactable * mac_tbl)1631bd671abSVishwanathapura, Niranjana static inline bool vema_mac_tbl_req_ok(struct opa_veswport_mactable *mac_tbl)
1641bd671abSVishwanathapura, Niranjana {
1651bd671abSVishwanathapura, Niranjana 	u16 offset, num_entries;
1661bd671abSVishwanathapura, Niranjana 	u16 req_entries = ((OPA_VNIC_EMA_DATA - sizeof(*mac_tbl)) /
1671bd671abSVishwanathapura, Niranjana 			   sizeof(mac_tbl->tbl_entries[0]));
1681bd671abSVishwanathapura, Niranjana 
1691bd671abSVishwanathapura, Niranjana 	offset = be16_to_cpu(mac_tbl->offset);
1701bd671abSVishwanathapura, Niranjana 	num_entries = be16_to_cpu(mac_tbl->num_entries);
1711bd671abSVishwanathapura, Niranjana 
1721bd671abSVishwanathapura, Niranjana 	return ((num_entries <= req_entries) &&
1731bd671abSVishwanathapura, Niranjana 		(offset + num_entries <= OPA_VNIC_MAC_TBL_MAX_ENTRIES));
1741bd671abSVishwanathapura, Niranjana }
1751bd671abSVishwanathapura, Niranjana 
1761bd671abSVishwanathapura, Niranjana /*
1771bd671abSVishwanathapura, Niranjana  * Return the power on default values in the port info structure
1781bd671abSVishwanathapura, Niranjana  * in big endian format as required by MAD.
1791bd671abSVishwanathapura, Niranjana  */
vema_get_pod_values(struct opa_veswport_info * port_info)1801bd671abSVishwanathapura, Niranjana static inline void vema_get_pod_values(struct opa_veswport_info *port_info)
1811bd671abSVishwanathapura, Niranjana {
1821bd671abSVishwanathapura, Niranjana 	memset(port_info, 0, sizeof(*port_info));
1831bd671abSVishwanathapura, Niranjana 	port_info->vport.max_mac_tbl_ent =
1841bd671abSVishwanathapura, Niranjana 		cpu_to_be16(OPA_VNIC_MAC_TBL_MAX_ENTRIES);
1851bd671abSVishwanathapura, Niranjana 	port_info->vport.max_smac_ent =
1861bd671abSVishwanathapura, Niranjana 		cpu_to_be16(OPA_VNIC_MAX_SMAC_LIMIT);
1871bd671abSVishwanathapura, Niranjana 	port_info->vport.oper_state = OPA_VNIC_STATE_DROP_ALL;
1881bd671abSVishwanathapura, Niranjana 	port_info->vport.config_state = OPA_VNIC_STATE_DROP_ALL;
1897f291d28SNiranjana Vishwanathapura 	port_info->vesw.eth_mtu = cpu_to_be16(ETH_DATA_LEN);
1901bd671abSVishwanathapura, Niranjana }
1911bd671abSVishwanathapura, Niranjana 
1921bd671abSVishwanathapura, Niranjana /**
1931bd671abSVishwanathapura, Niranjana  * vema_add_vport -- Add a new vnic port
1941bd671abSVishwanathapura, Niranjana  * @port: ptr to opa_vnic_vema_port struct
1951bd671abSVishwanathapura, Niranjana  * @vport_num: vnic port number (to be added)
1961bd671abSVishwanathapura, Niranjana  *
1971bd671abSVishwanathapura, Niranjana  * Return a pointer to the vnic adapter structure
1981bd671abSVishwanathapura, Niranjana  */
vema_add_vport(struct opa_vnic_vema_port * port,u8 vport_num)1991bd671abSVishwanathapura, Niranjana static struct opa_vnic_adapter *vema_add_vport(struct opa_vnic_vema_port *port,
2001bd671abSVishwanathapura, Niranjana 					       u8 vport_num)
2011bd671abSVishwanathapura, Niranjana {
2021bd671abSVishwanathapura, Niranjana 	struct opa_vnic_ctrl_port *cport = port->cport;
2031bd671abSVishwanathapura, Niranjana 	struct opa_vnic_adapter *adapter;
2041bd671abSVishwanathapura, Niranjana 
2051bd671abSVishwanathapura, Niranjana 	adapter = opa_vnic_add_netdev(cport->ibdev, port->port_num, vport_num);
2061bd671abSVishwanathapura, Niranjana 	if (!IS_ERR(adapter)) {
2071bd671abSVishwanathapura, Niranjana 		int rc;
2081bd671abSVishwanathapura, Niranjana 
2091bd671abSVishwanathapura, Niranjana 		adapter->cport = cport;
210fae7a699SMatthew Wilcox 		rc = xa_insert(&port->vports, vport_num, adapter, GFP_KERNEL);
2111bd671abSVishwanathapura, Niranjana 		if (rc < 0) {
2121bd671abSVishwanathapura, Niranjana 			opa_vnic_rem_netdev(adapter);
2131bd671abSVishwanathapura, Niranjana 			adapter = ERR_PTR(rc);
2141bd671abSVishwanathapura, Niranjana 		}
2151bd671abSVishwanathapura, Niranjana 	}
2161bd671abSVishwanathapura, Niranjana 
2171bd671abSVishwanathapura, Niranjana 	return adapter;
2181bd671abSVishwanathapura, Niranjana }
2191bd671abSVishwanathapura, Niranjana 
2201bd671abSVishwanathapura, Niranjana /**
2211bd671abSVishwanathapura, Niranjana  * vema_get_class_port_info -- Get class info for port
2221bd671abSVishwanathapura, Niranjana  * @port:  Port on whic MAD was received
2231bd671abSVishwanathapura, Niranjana  * @recvd_mad: pointer to the received mad
2241bd671abSVishwanathapura, Niranjana  * @rsp_mad:   pointer to respose mad
2251bd671abSVishwanathapura, Niranjana  *
2261bd671abSVishwanathapura, Niranjana  * This function copies the latest class port info value set for the
2271bd671abSVishwanathapura, Niranjana  * port and stores it for generating traps
2281bd671abSVishwanathapura, Niranjana  */
vema_get_class_port_info(struct opa_vnic_vema_port * port,struct opa_vnic_vema_mad * recvd_mad,struct opa_vnic_vema_mad * rsp_mad)2291bd671abSVishwanathapura, Niranjana static void vema_get_class_port_info(struct opa_vnic_vema_port *port,
2301bd671abSVishwanathapura, Niranjana 				     struct opa_vnic_vema_mad *recvd_mad,
2311bd671abSVishwanathapura, Niranjana 				     struct opa_vnic_vema_mad *rsp_mad)
2321bd671abSVishwanathapura, Niranjana {
2331bd671abSVishwanathapura, Niranjana 	struct opa_class_port_info *port_info;
2341bd671abSVishwanathapura, Niranjana 
2351bd671abSVishwanathapura, Niranjana 	port_info = (struct opa_class_port_info *)rsp_mad->data;
2361bd671abSVishwanathapura, Niranjana 	memcpy(port_info, &port->class_port_info, sizeof(*port_info));
23790eef9f7SZheng Yongjun 	port_info->base_version = OPA_MGMT_BASE_VERSION;
2381bd671abSVishwanathapura, Niranjana 	port_info->class_version = OPA_EMA_CLASS_VERSION;
2391bd671abSVishwanathapura, Niranjana 
2401bd671abSVishwanathapura, Niranjana 	/*
2411bd671abSVishwanathapura, Niranjana 	 * Set capability mask bit indicating agent generates traps,
2421bd671abSVishwanathapura, Niranjana 	 * and set the maximum number of VNIC ports supported.
2431bd671abSVishwanathapura, Niranjana 	 */
2441bd671abSVishwanathapura, Niranjana 	port_info->cap_mask = cpu_to_be16((OPA_VNIC_CLASS_CAP_TRAP |
2451bd671abSVishwanathapura, Niranjana 					   (OPA_VNIC_MAX_NUM_VPORT << 8)));
2461bd671abSVishwanathapura, Niranjana 
2471bd671abSVishwanathapura, Niranjana 	/*
2481bd671abSVishwanathapura, Niranjana 	 * Since a get routine is always sent by the EM first we
2491bd671abSVishwanathapura, Niranjana 	 * set the expected response time to
2501bd671abSVishwanathapura, Niranjana 	 * 4.096 usec * 2^18 == 1.0737 sec here.
2511bd671abSVishwanathapura, Niranjana 	 */
2521bd671abSVishwanathapura, Niranjana 	port_info->cap_mask2_resp_time = cpu_to_be32(18);
2531bd671abSVishwanathapura, Niranjana }
2541bd671abSVishwanathapura, Niranjana 
2551bd671abSVishwanathapura, Niranjana /**
2561bd671abSVishwanathapura, Niranjana  * vema_set_class_port_info -- Get class info for port
2571bd671abSVishwanathapura, Niranjana  * @port:  Port on whic MAD was received
2581bd671abSVishwanathapura, Niranjana  * @recvd_mad: pointer to the received mad
2591bd671abSVishwanathapura, Niranjana  * @rsp_mad:   pointer to respose mad
2601bd671abSVishwanathapura, Niranjana  *
2611bd671abSVishwanathapura, Niranjana  * This function updates the port class info for the specific vnic
2621bd671abSVishwanathapura, Niranjana  * and sets up the response mad data
2631bd671abSVishwanathapura, Niranjana  */
vema_set_class_port_info(struct opa_vnic_vema_port * port,struct opa_vnic_vema_mad * recvd_mad,struct opa_vnic_vema_mad * rsp_mad)2641bd671abSVishwanathapura, Niranjana static void vema_set_class_port_info(struct opa_vnic_vema_port *port,
2651bd671abSVishwanathapura, Niranjana 				     struct opa_vnic_vema_mad *recvd_mad,
2661bd671abSVishwanathapura, Niranjana 				     struct opa_vnic_vema_mad *rsp_mad)
2671bd671abSVishwanathapura, Niranjana {
2681bd671abSVishwanathapura, Niranjana 	memcpy(&port->class_port_info, recvd_mad->data,
2691bd671abSVishwanathapura, Niranjana 	       sizeof(port->class_port_info));
2701bd671abSVishwanathapura, Niranjana 
2711bd671abSVishwanathapura, Niranjana 	vema_get_class_port_info(port, recvd_mad, rsp_mad);
2721bd671abSVishwanathapura, Niranjana }
2731bd671abSVishwanathapura, Niranjana 
2741bd671abSVishwanathapura, Niranjana /**
2751bd671abSVishwanathapura, Niranjana  * vema_get_veswport_info -- Get veswport info
2761bd671abSVishwanathapura, Niranjana  * @port:      source port on which MAD was received
2771bd671abSVishwanathapura, Niranjana  * @recvd_mad: pointer to the received mad
2781bd671abSVishwanathapura, Niranjana  * @rsp_mad:   pointer to respose mad
2791bd671abSVishwanathapura, Niranjana  */
vema_get_veswport_info(struct opa_vnic_vema_port * port,struct opa_vnic_vema_mad * recvd_mad,struct opa_vnic_vema_mad * rsp_mad)2801bd671abSVishwanathapura, Niranjana static void vema_get_veswport_info(struct opa_vnic_vema_port *port,
2811bd671abSVishwanathapura, Niranjana 				   struct opa_vnic_vema_mad *recvd_mad,
2821bd671abSVishwanathapura, Niranjana 				   struct opa_vnic_vema_mad *rsp_mad)
2831bd671abSVishwanathapura, Niranjana {
2841bd671abSVishwanathapura, Niranjana 	struct opa_veswport_info *port_info =
2851bd671abSVishwanathapura, Niranjana 				  (struct opa_veswport_info *)rsp_mad->data;
2861bd671abSVishwanathapura, Niranjana 	struct opa_vnic_adapter *adapter;
2871bd671abSVishwanathapura, Niranjana 
2881bd671abSVishwanathapura, Niranjana 	adapter = vema_get_vport_adapter(recvd_mad, port);
2891bd671abSVishwanathapura, Niranjana 	if (adapter) {
2901bd671abSVishwanathapura, Niranjana 		memset(port_info, 0, sizeof(*port_info));
2911bd671abSVishwanathapura, Niranjana 		opa_vnic_get_vesw_info(adapter, &port_info->vesw);
2921bd671abSVishwanathapura, Niranjana 		opa_vnic_get_per_veswport_info(adapter,
2931bd671abSVishwanathapura, Niranjana 					       &port_info->vport);
2941bd671abSVishwanathapura, Niranjana 	} else {
2951bd671abSVishwanathapura, Niranjana 		vema_get_pod_values(port_info);
2961bd671abSVishwanathapura, Niranjana 	}
2971bd671abSVishwanathapura, Niranjana }
2981bd671abSVishwanathapura, Niranjana 
2991bd671abSVishwanathapura, Niranjana /**
3001bd671abSVishwanathapura, Niranjana  * vema_set_veswport_info -- Set veswport info
3011bd671abSVishwanathapura, Niranjana  * @port:      source port on which MAD was received
3021bd671abSVishwanathapura, Niranjana  * @recvd_mad: pointer to the received mad
3031bd671abSVishwanathapura, Niranjana  * @rsp_mad:   pointer to respose mad
3041bd671abSVishwanathapura, Niranjana  *
3051bd671abSVishwanathapura, Niranjana  * This function gets the port class infor for vnic
3061bd671abSVishwanathapura, Niranjana  */
vema_set_veswport_info(struct opa_vnic_vema_port * port,struct opa_vnic_vema_mad * recvd_mad,struct opa_vnic_vema_mad * rsp_mad)3071bd671abSVishwanathapura, Niranjana static void vema_set_veswport_info(struct opa_vnic_vema_port *port,
3081bd671abSVishwanathapura, Niranjana 				   struct opa_vnic_vema_mad *recvd_mad,
3091bd671abSVishwanathapura, Niranjana 				   struct opa_vnic_vema_mad *rsp_mad)
3101bd671abSVishwanathapura, Niranjana {
3111bd671abSVishwanathapura, Niranjana 	struct opa_vnic_ctrl_port *cport = port->cport;
3121bd671abSVishwanathapura, Niranjana 	struct opa_veswport_info *port_info;
3131bd671abSVishwanathapura, Niranjana 	struct opa_vnic_adapter *adapter;
3141bd671abSVishwanathapura, Niranjana 	u8 vport_num;
3151bd671abSVishwanathapura, Niranjana 
3161bd671abSVishwanathapura, Niranjana 	vport_num = vema_get_vport_num(recvd_mad);
3171bd671abSVishwanathapura, Niranjana 
3181bd671abSVishwanathapura, Niranjana 	adapter = vema_get_vport_adapter(recvd_mad, port);
3191bd671abSVishwanathapura, Niranjana 	if (!adapter) {
3201bd671abSVishwanathapura, Niranjana 		adapter = vema_add_vport(port, vport_num);
3211bd671abSVishwanathapura, Niranjana 		if (IS_ERR(adapter)) {
3221bd671abSVishwanathapura, Niranjana 			c_err("failed to add vport %d: %ld\n",
3231bd671abSVishwanathapura, Niranjana 			      vport_num, PTR_ERR(adapter));
3241bd671abSVishwanathapura, Niranjana 			goto err_exit;
3251bd671abSVishwanathapura, Niranjana 		}
3261bd671abSVishwanathapura, Niranjana 	}
3271bd671abSVishwanathapura, Niranjana 
3281bd671abSVishwanathapura, Niranjana 	port_info = (struct opa_veswport_info *)recvd_mad->data;
3291bd671abSVishwanathapura, Niranjana 	opa_vnic_set_vesw_info(adapter, &port_info->vesw);
3301bd671abSVishwanathapura, Niranjana 	opa_vnic_set_per_veswport_info(adapter, &port_info->vport);
3311bd671abSVishwanathapura, Niranjana 
3321bd671abSVishwanathapura, Niranjana 	/* Process the new config settings */
3331bd671abSVishwanathapura, Niranjana 	opa_vnic_process_vema_config(adapter);
3341bd671abSVishwanathapura, Niranjana 
3351bd671abSVishwanathapura, Niranjana 	vema_get_veswport_info(port, recvd_mad, rsp_mad);
3361bd671abSVishwanathapura, Niranjana 	return;
3371bd671abSVishwanathapura, Niranjana 
3381bd671abSVishwanathapura, Niranjana err_exit:
3391bd671abSVishwanathapura, Niranjana 	rsp_mad->mad_hdr.status = OPA_VNIC_INVAL_ATTR;
3401bd671abSVishwanathapura, Niranjana }
3411bd671abSVishwanathapura, Niranjana 
3421bd671abSVishwanathapura, Niranjana /**
3431bd671abSVishwanathapura, Niranjana  * vema_get_mac_entries -- Get MAC entries in VNIC MAC table
3441bd671abSVishwanathapura, Niranjana  * @port:      source port on which MAD was received
3451bd671abSVishwanathapura, Niranjana  * @recvd_mad: pointer to the received mad
3461bd671abSVishwanathapura, Niranjana  * @rsp_mad:   pointer to respose mad
3471bd671abSVishwanathapura, Niranjana  *
3481bd671abSVishwanathapura, Niranjana  * This function gets the MAC entries that are programmed into
3491bd671abSVishwanathapura, Niranjana  * the VNIC MAC forwarding table. It checks for the validity of
3501bd671abSVishwanathapura, Niranjana  * the index into the MAC table and the number of entries that
3511bd671abSVishwanathapura, Niranjana  * are to be retrieved.
3521bd671abSVishwanathapura, Niranjana  */
vema_get_mac_entries(struct opa_vnic_vema_port * port,struct opa_vnic_vema_mad * recvd_mad,struct opa_vnic_vema_mad * rsp_mad)3531bd671abSVishwanathapura, Niranjana static void vema_get_mac_entries(struct opa_vnic_vema_port *port,
3541bd671abSVishwanathapura, Niranjana 				 struct opa_vnic_vema_mad *recvd_mad,
3551bd671abSVishwanathapura, Niranjana 				 struct opa_vnic_vema_mad *rsp_mad)
3561bd671abSVishwanathapura, Niranjana {
3571bd671abSVishwanathapura, Niranjana 	struct opa_veswport_mactable *mac_tbl_in, *mac_tbl_out;
3581bd671abSVishwanathapura, Niranjana 	struct opa_vnic_adapter *adapter;
3591bd671abSVishwanathapura, Niranjana 
3601bd671abSVishwanathapura, Niranjana 	adapter = vema_get_vport_adapter(recvd_mad, port);
3611bd671abSVishwanathapura, Niranjana 	if (!adapter) {
3621bd671abSVishwanathapura, Niranjana 		rsp_mad->mad_hdr.status = OPA_VNIC_INVAL_ATTR;
3631bd671abSVishwanathapura, Niranjana 		return;
3641bd671abSVishwanathapura, Niranjana 	}
3651bd671abSVishwanathapura, Niranjana 
3661bd671abSVishwanathapura, Niranjana 	mac_tbl_in = (struct opa_veswport_mactable *)recvd_mad->data;
3671bd671abSVishwanathapura, Niranjana 	mac_tbl_out = (struct opa_veswport_mactable *)rsp_mad->data;
3681bd671abSVishwanathapura, Niranjana 
3691bd671abSVishwanathapura, Niranjana 	if (vema_mac_tbl_req_ok(mac_tbl_in)) {
3701bd671abSVishwanathapura, Niranjana 		mac_tbl_out->offset = mac_tbl_in->offset;
3711bd671abSVishwanathapura, Niranjana 		mac_tbl_out->num_entries = mac_tbl_in->num_entries;
3721bd671abSVishwanathapura, Niranjana 		opa_vnic_query_mac_tbl(adapter, mac_tbl_out);
3731bd671abSVishwanathapura, Niranjana 	} else {
3741bd671abSVishwanathapura, Niranjana 		rsp_mad->mad_hdr.status = OPA_VNIC_INVAL_ATTR;
3751bd671abSVishwanathapura, Niranjana 	}
3761bd671abSVishwanathapura, Niranjana }
3771bd671abSVishwanathapura, Niranjana 
3781bd671abSVishwanathapura, Niranjana /**
3791bd671abSVishwanathapura, Niranjana  * vema_set_mac_entries -- Set MAC entries in VNIC MAC table
3801bd671abSVishwanathapura, Niranjana  * @port:      source port on which MAD was received
3811bd671abSVishwanathapura, Niranjana  * @recvd_mad: pointer to the received mad
3821bd671abSVishwanathapura, Niranjana  * @rsp_mad:   pointer to respose mad
3831bd671abSVishwanathapura, Niranjana  *
3841bd671abSVishwanathapura, Niranjana  * This function sets the MAC entries in the VNIC forwarding table
3851bd671abSVishwanathapura, Niranjana  * It checks for the validity of the index and the number of forwarding
3861bd671abSVishwanathapura, Niranjana  * table entries to be programmed.
3871bd671abSVishwanathapura, Niranjana  */
vema_set_mac_entries(struct opa_vnic_vema_port * port,struct opa_vnic_vema_mad * recvd_mad,struct opa_vnic_vema_mad * rsp_mad)3881bd671abSVishwanathapura, Niranjana static void vema_set_mac_entries(struct opa_vnic_vema_port *port,
3891bd671abSVishwanathapura, Niranjana 				 struct opa_vnic_vema_mad *recvd_mad,
3901bd671abSVishwanathapura, Niranjana 				 struct opa_vnic_vema_mad *rsp_mad)
3911bd671abSVishwanathapura, Niranjana {
3921bd671abSVishwanathapura, Niranjana 	struct opa_veswport_mactable *mac_tbl;
3931bd671abSVishwanathapura, Niranjana 	struct opa_vnic_adapter *adapter;
3941bd671abSVishwanathapura, Niranjana 
3951bd671abSVishwanathapura, Niranjana 	adapter = vema_get_vport_adapter(recvd_mad, port);
3961bd671abSVishwanathapura, Niranjana 	if (!adapter) {
3971bd671abSVishwanathapura, Niranjana 		rsp_mad->mad_hdr.status = OPA_VNIC_INVAL_ATTR;
3981bd671abSVishwanathapura, Niranjana 		return;
3991bd671abSVishwanathapura, Niranjana 	}
4001bd671abSVishwanathapura, Niranjana 
4011bd671abSVishwanathapura, Niranjana 	mac_tbl = (struct opa_veswport_mactable *)recvd_mad->data;
4021bd671abSVishwanathapura, Niranjana 	if (vema_mac_tbl_req_ok(mac_tbl)) {
4031bd671abSVishwanathapura, Niranjana 		if (opa_vnic_update_mac_tbl(adapter, mac_tbl))
4041bd671abSVishwanathapura, Niranjana 			rsp_mad->mad_hdr.status = OPA_VNIC_UNSUP_ATTR;
4051bd671abSVishwanathapura, Niranjana 	} else {
4061bd671abSVishwanathapura, Niranjana 		rsp_mad->mad_hdr.status = OPA_VNIC_UNSUP_ATTR;
4071bd671abSVishwanathapura, Niranjana 	}
4081bd671abSVishwanathapura, Niranjana 	vema_get_mac_entries(port, recvd_mad, rsp_mad);
4091bd671abSVishwanathapura, Niranjana }
4101bd671abSVishwanathapura, Niranjana 
4111bd671abSVishwanathapura, Niranjana /**
4121bd671abSVishwanathapura, Niranjana  * vema_set_delete_vesw -- Reset VESW info to POD values
4131bd671abSVishwanathapura, Niranjana  * @port:      source port on which MAD was received
4141bd671abSVishwanathapura, Niranjana  * @recvd_mad: pointer to the received mad
4151bd671abSVishwanathapura, Niranjana  * @rsp_mad:   pointer to respose mad
4161bd671abSVishwanathapura, Niranjana  *
4171bd671abSVishwanathapura, Niranjana  * This function clears all the fields of veswport info for the requested vesw
4181bd671abSVishwanathapura, Niranjana  * and sets them back to the power-on default values. It does not delete the
4191bd671abSVishwanathapura, Niranjana  * vesw.
4201bd671abSVishwanathapura, Niranjana  */
vema_set_delete_vesw(struct opa_vnic_vema_port * port,struct opa_vnic_vema_mad * recvd_mad,struct opa_vnic_vema_mad * rsp_mad)4211bd671abSVishwanathapura, Niranjana static void vema_set_delete_vesw(struct opa_vnic_vema_port *port,
4221bd671abSVishwanathapura, Niranjana 				 struct opa_vnic_vema_mad *recvd_mad,
4231bd671abSVishwanathapura, Niranjana 				 struct opa_vnic_vema_mad *rsp_mad)
4241bd671abSVishwanathapura, Niranjana {
4251bd671abSVishwanathapura, Niranjana 	struct opa_veswport_info *port_info =
4261bd671abSVishwanathapura, Niranjana 				  (struct opa_veswport_info *)rsp_mad->data;
4271bd671abSVishwanathapura, Niranjana 	struct opa_vnic_adapter *adapter;
4281bd671abSVishwanathapura, Niranjana 
4291bd671abSVishwanathapura, Niranjana 	adapter = vema_get_vport_adapter(recvd_mad, port);
4301bd671abSVishwanathapura, Niranjana 	if (!adapter) {
4311bd671abSVishwanathapura, Niranjana 		rsp_mad->mad_hdr.status = OPA_VNIC_INVAL_ATTR;
4321bd671abSVishwanathapura, Niranjana 		return;
4331bd671abSVishwanathapura, Niranjana 	}
4341bd671abSVishwanathapura, Niranjana 
4351bd671abSVishwanathapura, Niranjana 	vema_get_pod_values(port_info);
4361bd671abSVishwanathapura, Niranjana 	opa_vnic_set_vesw_info(adapter, &port_info->vesw);
4371bd671abSVishwanathapura, Niranjana 	opa_vnic_set_per_veswport_info(adapter, &port_info->vport);
4381bd671abSVishwanathapura, Niranjana 
4391bd671abSVishwanathapura, Niranjana 	/* Process the new config settings */
4401bd671abSVishwanathapura, Niranjana 	opa_vnic_process_vema_config(adapter);
4411bd671abSVishwanathapura, Niranjana 
4421bd671abSVishwanathapura, Niranjana 	opa_vnic_release_mac_tbl(adapter);
4431bd671abSVishwanathapura, Niranjana 
4441bd671abSVishwanathapura, Niranjana 	vema_get_veswport_info(port, recvd_mad, rsp_mad);
4451bd671abSVishwanathapura, Niranjana }
4461bd671abSVishwanathapura, Niranjana 
4471bd671abSVishwanathapura, Niranjana /**
4481bd671abSVishwanathapura, Niranjana  * vema_get_mac_list -- Get the unicast/multicast macs.
4491bd671abSVishwanathapura, Niranjana  * @port:      source port on which MAD was received
4501bd671abSVishwanathapura, Niranjana  * @recvd_mad: Received mad contains fields to set vnic parameters
4511bd671abSVishwanathapura, Niranjana  * @rsp_mad:   Response mad to be built
4521bd671abSVishwanathapura, Niranjana  * @attr_id:   Attribute ID indicating multicast or unicast mac list
4531bd671abSVishwanathapura, Niranjana  */
vema_get_mac_list(struct opa_vnic_vema_port * port,struct opa_vnic_vema_mad * recvd_mad,struct opa_vnic_vema_mad * rsp_mad,u16 attr_id)4541bd671abSVishwanathapura, Niranjana static void vema_get_mac_list(struct opa_vnic_vema_port *port,
4551bd671abSVishwanathapura, Niranjana 			      struct opa_vnic_vema_mad *recvd_mad,
4561bd671abSVishwanathapura, Niranjana 			      struct opa_vnic_vema_mad *rsp_mad,
4571bd671abSVishwanathapura, Niranjana 			      u16 attr_id)
4581bd671abSVishwanathapura, Niranjana {
4591bd671abSVishwanathapura, Niranjana 	struct opa_veswport_iface_macs *macs_in, *macs_out;
4601bd671abSVishwanathapura, Niranjana 	int max_entries = (OPA_VNIC_EMA_DATA - sizeof(*macs_out)) / ETH_ALEN;
4611bd671abSVishwanathapura, Niranjana 	struct opa_vnic_adapter *adapter;
4621bd671abSVishwanathapura, Niranjana 
4631bd671abSVishwanathapura, Niranjana 	adapter = vema_get_vport_adapter(recvd_mad, port);
4641bd671abSVishwanathapura, Niranjana 	if (!adapter) {
4651bd671abSVishwanathapura, Niranjana 		rsp_mad->mad_hdr.status = OPA_VNIC_INVAL_ATTR;
4661bd671abSVishwanathapura, Niranjana 		return;
4671bd671abSVishwanathapura, Niranjana 	}
4681bd671abSVishwanathapura, Niranjana 
4691bd671abSVishwanathapura, Niranjana 	macs_in = (struct opa_veswport_iface_macs *)recvd_mad->data;
4701bd671abSVishwanathapura, Niranjana 	macs_out = (struct opa_veswport_iface_macs *)rsp_mad->data;
4711bd671abSVishwanathapura, Niranjana 
4721bd671abSVishwanathapura, Niranjana 	macs_out->start_idx = macs_in->start_idx;
4731bd671abSVishwanathapura, Niranjana 	if (macs_in->num_macs_in_msg)
4741bd671abSVishwanathapura, Niranjana 		macs_out->num_macs_in_msg = macs_in->num_macs_in_msg;
4751bd671abSVishwanathapura, Niranjana 	else
4761bd671abSVishwanathapura, Niranjana 		macs_out->num_macs_in_msg = cpu_to_be16(max_entries);
4771bd671abSVishwanathapura, Niranjana 
4781bd671abSVishwanathapura, Niranjana 	if (attr_id == OPA_EM_ATTR_IFACE_MCAST_MACS)
4791bd671abSVishwanathapura, Niranjana 		opa_vnic_query_mcast_macs(adapter, macs_out);
4801bd671abSVishwanathapura, Niranjana 	else
4811bd671abSVishwanathapura, Niranjana 		opa_vnic_query_ucast_macs(adapter, macs_out);
4821bd671abSVishwanathapura, Niranjana }
4831bd671abSVishwanathapura, Niranjana 
4841bd671abSVishwanathapura, Niranjana /**
4851bd671abSVishwanathapura, Niranjana  * vema_get_summary_counters -- Gets summary counters.
4861bd671abSVishwanathapura, Niranjana  * @port:      source port on which MAD was received
4871bd671abSVishwanathapura, Niranjana  * @recvd_mad: Received mad contains fields to set vnic parameters
4881bd671abSVishwanathapura, Niranjana  * @rsp_mad:   Response mad to be built
4891bd671abSVishwanathapura, Niranjana  */
vema_get_summary_counters(struct opa_vnic_vema_port * port,struct opa_vnic_vema_mad * recvd_mad,struct opa_vnic_vema_mad * rsp_mad)4901bd671abSVishwanathapura, Niranjana static void vema_get_summary_counters(struct opa_vnic_vema_port *port,
4911bd671abSVishwanathapura, Niranjana 				      struct opa_vnic_vema_mad *recvd_mad,
4921bd671abSVishwanathapura, Niranjana 				      struct opa_vnic_vema_mad *rsp_mad)
4931bd671abSVishwanathapura, Niranjana {
4941bd671abSVishwanathapura, Niranjana 	struct opa_veswport_summary_counters *cntrs;
4951bd671abSVishwanathapura, Niranjana 	struct opa_vnic_adapter *adapter;
4961bd671abSVishwanathapura, Niranjana 
4971bd671abSVishwanathapura, Niranjana 	adapter = vema_get_vport_adapter(recvd_mad, port);
4981bd671abSVishwanathapura, Niranjana 	if (adapter) {
4991bd671abSVishwanathapura, Niranjana 		cntrs = (struct opa_veswport_summary_counters *)rsp_mad->data;
5001bd671abSVishwanathapura, Niranjana 		opa_vnic_get_summary_counters(adapter, cntrs);
5011bd671abSVishwanathapura, Niranjana 	} else {
5021bd671abSVishwanathapura, Niranjana 		rsp_mad->mad_hdr.status = OPA_VNIC_INVAL_ATTR;
5031bd671abSVishwanathapura, Niranjana 	}
5041bd671abSVishwanathapura, Niranjana }
5051bd671abSVishwanathapura, Niranjana 
5061bd671abSVishwanathapura, Niranjana /**
5071bd671abSVishwanathapura, Niranjana  * vema_get_error_counters -- Gets summary counters.
5081bd671abSVishwanathapura, Niranjana  * @port:      source port on which MAD was received
5091bd671abSVishwanathapura, Niranjana  * @recvd_mad: Received mad contains fields to set vnic parameters
5101bd671abSVishwanathapura, Niranjana  * @rsp_mad:   Response mad to be built
5111bd671abSVishwanathapura, Niranjana  */
vema_get_error_counters(struct opa_vnic_vema_port * port,struct opa_vnic_vema_mad * recvd_mad,struct opa_vnic_vema_mad * rsp_mad)5121bd671abSVishwanathapura, Niranjana static void vema_get_error_counters(struct opa_vnic_vema_port *port,
5131bd671abSVishwanathapura, Niranjana 				    struct opa_vnic_vema_mad *recvd_mad,
5141bd671abSVishwanathapura, Niranjana 				    struct opa_vnic_vema_mad *rsp_mad)
5151bd671abSVishwanathapura, Niranjana {
5161bd671abSVishwanathapura, Niranjana 	struct opa_veswport_error_counters *cntrs;
5171bd671abSVishwanathapura, Niranjana 	struct opa_vnic_adapter *adapter;
5181bd671abSVishwanathapura, Niranjana 
5191bd671abSVishwanathapura, Niranjana 	adapter = vema_get_vport_adapter(recvd_mad, port);
5201bd671abSVishwanathapura, Niranjana 	if (adapter) {
5211bd671abSVishwanathapura, Niranjana 		cntrs = (struct opa_veswport_error_counters *)rsp_mad->data;
5221bd671abSVishwanathapura, Niranjana 		opa_vnic_get_error_counters(adapter, cntrs);
5231bd671abSVishwanathapura, Niranjana 	} else {
5241bd671abSVishwanathapura, Niranjana 		rsp_mad->mad_hdr.status = OPA_VNIC_INVAL_ATTR;
5251bd671abSVishwanathapura, Niranjana 	}
5261bd671abSVishwanathapura, Niranjana }
5271bd671abSVishwanathapura, Niranjana 
5281bd671abSVishwanathapura, Niranjana /**
5291bd671abSVishwanathapura, Niranjana  * vema_get -- Process received get MAD
5301bd671abSVishwanathapura, Niranjana  * @port:      source port on which MAD was received
5311bd671abSVishwanathapura, Niranjana  * @recvd_mad: Received mad
5321bd671abSVishwanathapura, Niranjana  * @rsp_mad:   Response mad to be built
5331bd671abSVishwanathapura, Niranjana  */
vema_get(struct opa_vnic_vema_port * port,struct opa_vnic_vema_mad * recvd_mad,struct opa_vnic_vema_mad * rsp_mad)5341bd671abSVishwanathapura, Niranjana static void vema_get(struct opa_vnic_vema_port *port,
5351bd671abSVishwanathapura, Niranjana 		     struct opa_vnic_vema_mad *recvd_mad,
5361bd671abSVishwanathapura, Niranjana 		     struct opa_vnic_vema_mad *rsp_mad)
5371bd671abSVishwanathapura, Niranjana {
5381bd671abSVishwanathapura, Niranjana 	u16 attr_id = be16_to_cpu(recvd_mad->mad_hdr.attr_id);
5391bd671abSVishwanathapura, Niranjana 
5401bd671abSVishwanathapura, Niranjana 	switch (attr_id) {
5411bd671abSVishwanathapura, Niranjana 	case OPA_EM_ATTR_CLASS_PORT_INFO:
5421bd671abSVishwanathapura, Niranjana 		vema_get_class_port_info(port, recvd_mad, rsp_mad);
5431bd671abSVishwanathapura, Niranjana 		break;
5441bd671abSVishwanathapura, Niranjana 	case OPA_EM_ATTR_VESWPORT_INFO:
5451bd671abSVishwanathapura, Niranjana 		vema_get_veswport_info(port, recvd_mad, rsp_mad);
5461bd671abSVishwanathapura, Niranjana 		break;
5471bd671abSVishwanathapura, Niranjana 	case OPA_EM_ATTR_VESWPORT_MAC_ENTRIES:
5481bd671abSVishwanathapura, Niranjana 		vema_get_mac_entries(port, recvd_mad, rsp_mad);
5491bd671abSVishwanathapura, Niranjana 		break;
5501bd671abSVishwanathapura, Niranjana 	case OPA_EM_ATTR_IFACE_UCAST_MACS:
5511bd671abSVishwanathapura, Niranjana 	case OPA_EM_ATTR_IFACE_MCAST_MACS:
5521bd671abSVishwanathapura, Niranjana 		vema_get_mac_list(port, recvd_mad, rsp_mad, attr_id);
5531bd671abSVishwanathapura, Niranjana 		break;
5541bd671abSVishwanathapura, Niranjana 	case OPA_EM_ATTR_VESWPORT_SUMMARY_COUNTERS:
5551bd671abSVishwanathapura, Niranjana 		vema_get_summary_counters(port, recvd_mad, rsp_mad);
5561bd671abSVishwanathapura, Niranjana 		break;
5571bd671abSVishwanathapura, Niranjana 	case OPA_EM_ATTR_VESWPORT_ERROR_COUNTERS:
5581bd671abSVishwanathapura, Niranjana 		vema_get_error_counters(port, recvd_mad, rsp_mad);
5591bd671abSVishwanathapura, Niranjana 		break;
5601bd671abSVishwanathapura, Niranjana 	default:
5611bd671abSVishwanathapura, Niranjana 		rsp_mad->mad_hdr.status = OPA_VNIC_UNSUP_ATTR;
5621bd671abSVishwanathapura, Niranjana 		break;
5631bd671abSVishwanathapura, Niranjana 	}
5641bd671abSVishwanathapura, Niranjana }
5651bd671abSVishwanathapura, Niranjana 
5661bd671abSVishwanathapura, Niranjana /**
5671bd671abSVishwanathapura, Niranjana  * vema_set -- Process received set MAD
5681bd671abSVishwanathapura, Niranjana  * @port:      source port on which MAD was received
5691bd671abSVishwanathapura, Niranjana  * @recvd_mad: Received mad contains fields to set vnic parameters
5701bd671abSVishwanathapura, Niranjana  * @rsp_mad:   Response mad to be built
5711bd671abSVishwanathapura, Niranjana  */
vema_set(struct opa_vnic_vema_port * port,struct opa_vnic_vema_mad * recvd_mad,struct opa_vnic_vema_mad * rsp_mad)5721bd671abSVishwanathapura, Niranjana static void vema_set(struct opa_vnic_vema_port *port,
5731bd671abSVishwanathapura, Niranjana 		     struct opa_vnic_vema_mad *recvd_mad,
5741bd671abSVishwanathapura, Niranjana 		     struct opa_vnic_vema_mad *rsp_mad)
5751bd671abSVishwanathapura, Niranjana {
5761bd671abSVishwanathapura, Niranjana 	u16 attr_id = be16_to_cpu(recvd_mad->mad_hdr.attr_id);
5771bd671abSVishwanathapura, Niranjana 
5781bd671abSVishwanathapura, Niranjana 	switch (attr_id) {
5791bd671abSVishwanathapura, Niranjana 	case OPA_EM_ATTR_CLASS_PORT_INFO:
5801bd671abSVishwanathapura, Niranjana 		vema_set_class_port_info(port, recvd_mad, rsp_mad);
5811bd671abSVishwanathapura, Niranjana 		break;
5821bd671abSVishwanathapura, Niranjana 	case OPA_EM_ATTR_VESWPORT_INFO:
5831bd671abSVishwanathapura, Niranjana 		vema_set_veswport_info(port, recvd_mad, rsp_mad);
5841bd671abSVishwanathapura, Niranjana 		break;
5851bd671abSVishwanathapura, Niranjana 	case OPA_EM_ATTR_VESWPORT_MAC_ENTRIES:
5861bd671abSVishwanathapura, Niranjana 		vema_set_mac_entries(port, recvd_mad, rsp_mad);
5871bd671abSVishwanathapura, Niranjana 		break;
5881bd671abSVishwanathapura, Niranjana 	case OPA_EM_ATTR_DELETE_VESW:
5891bd671abSVishwanathapura, Niranjana 		vema_set_delete_vesw(port, recvd_mad, rsp_mad);
5901bd671abSVishwanathapura, Niranjana 		break;
5911bd671abSVishwanathapura, Niranjana 	default:
5921bd671abSVishwanathapura, Niranjana 		rsp_mad->mad_hdr.status = OPA_VNIC_UNSUP_ATTR;
5931bd671abSVishwanathapura, Niranjana 		break;
5941bd671abSVishwanathapura, Niranjana 	}
5951bd671abSVishwanathapura, Niranjana }
5961bd671abSVishwanathapura, Niranjana 
5971bd671abSVishwanathapura, Niranjana /**
5981bd671abSVishwanathapura, Niranjana  * vema_send -- Send handler for VEMA MAD agent
5991bd671abSVishwanathapura, Niranjana  * @mad_agent: pointer to the mad agent
6001bd671abSVishwanathapura, Niranjana  * @mad_wc:    pointer to mad send work completion information
6011bd671abSVishwanathapura, Niranjana  *
6021bd671abSVishwanathapura, Niranjana  * Free all the data structures associated with the sent MAD
6031bd671abSVishwanathapura, Niranjana  */
vema_send(struct ib_mad_agent * mad_agent,struct ib_mad_send_wc * mad_wc)6041bd671abSVishwanathapura, Niranjana static void vema_send(struct ib_mad_agent *mad_agent,
6051bd671abSVishwanathapura, Niranjana 		      struct ib_mad_send_wc *mad_wc)
6061bd671abSVishwanathapura, Niranjana {
6072553ba21SGal Pressman 	rdma_destroy_ah(mad_wc->send_buf->ah, RDMA_DESTROY_AH_SLEEPABLE);
6081bd671abSVishwanathapura, Niranjana 	ib_free_send_mad(mad_wc->send_buf);
6091bd671abSVishwanathapura, Niranjana }
6101bd671abSVishwanathapura, Niranjana 
6111bd671abSVishwanathapura, Niranjana /**
6121bd671abSVishwanathapura, Niranjana  * vema_recv -- Recv handler for VEMA MAD agent
6131bd671abSVishwanathapura, Niranjana  * @mad_agent: pointer to the mad agent
6141bd671abSVishwanathapura, Niranjana  * @send_buf: Send buffer if found, else NULL
6151bd671abSVishwanathapura, Niranjana  * @mad_wc:    pointer to mad send work completion information
6161bd671abSVishwanathapura, Niranjana  *
6171bd671abSVishwanathapura, Niranjana  * Handle only set and get methods and respond to other methods
6181bd671abSVishwanathapura, Niranjana  * as unsupported. Allocate response buffer and address handle
6191bd671abSVishwanathapura, Niranjana  * for the response MAD.
6201bd671abSVishwanathapura, Niranjana  */
vema_recv(struct ib_mad_agent * mad_agent,struct ib_mad_send_buf * send_buf,struct ib_mad_recv_wc * mad_wc)6211bd671abSVishwanathapura, Niranjana static void vema_recv(struct ib_mad_agent *mad_agent,
6221bd671abSVishwanathapura, Niranjana 		      struct ib_mad_send_buf *send_buf,
6231bd671abSVishwanathapura, Niranjana 		      struct ib_mad_recv_wc *mad_wc)
6241bd671abSVishwanathapura, Niranjana {
6251bd671abSVishwanathapura, Niranjana 	struct opa_vnic_vema_port *port;
6261bd671abSVishwanathapura, Niranjana 	struct ib_ah              *ah;
6271bd671abSVishwanathapura, Niranjana 	struct ib_mad_send_buf    *rsp;
6281bd671abSVishwanathapura, Niranjana 	struct opa_vnic_vema_mad  *vema_mad;
6291bd671abSVishwanathapura, Niranjana 
6301bd671abSVishwanathapura, Niranjana 	if (!mad_wc || !mad_wc->recv_buf.mad)
6311bd671abSVishwanathapura, Niranjana 		return;
6321bd671abSVishwanathapura, Niranjana 
6331bd671abSVishwanathapura, Niranjana 	port = mad_agent->context;
6341bd671abSVishwanathapura, Niranjana 	ah = ib_create_ah_from_wc(mad_agent->qp->pd, mad_wc->wc,
6351bd671abSVishwanathapura, Niranjana 				  mad_wc->recv_buf.grh, mad_agent->port_num);
6361bd671abSVishwanathapura, Niranjana 	if (IS_ERR(ah))
6371bd671abSVishwanathapura, Niranjana 		goto free_recv_mad;
6381bd671abSVishwanathapura, Niranjana 
6391bd671abSVishwanathapura, Niranjana 	rsp = ib_create_send_mad(mad_agent, mad_wc->wc->src_qp,
6401bd671abSVishwanathapura, Niranjana 				 mad_wc->wc->pkey_index, 0,
6411bd671abSVishwanathapura, Niranjana 				 IB_MGMT_VENDOR_HDR, OPA_VNIC_EMA_DATA,
6421bd671abSVishwanathapura, Niranjana 				 GFP_KERNEL, OPA_MGMT_BASE_VERSION);
6431bd671abSVishwanathapura, Niranjana 	if (IS_ERR(rsp))
6441bd671abSVishwanathapura, Niranjana 		goto err_rsp;
6451bd671abSVishwanathapura, Niranjana 
6461bd671abSVishwanathapura, Niranjana 	rsp->ah = ah;
6471bd671abSVishwanathapura, Niranjana 	vema_mad = rsp->mad;
6481bd671abSVishwanathapura, Niranjana 	memcpy(vema_mad, mad_wc->recv_buf.mad, IB_MGMT_VENDOR_HDR);
6491bd671abSVishwanathapura, Niranjana 	vema_mad->mad_hdr.method = IB_MGMT_METHOD_GET_RESP;
6501bd671abSVishwanathapura, Niranjana 	vema_mad->mad_hdr.status = 0;
6511bd671abSVishwanathapura, Niranjana 
6521bd671abSVishwanathapura, Niranjana 	/* Lock ensures network adapter is not removed */
6531bd671abSVishwanathapura, Niranjana 	mutex_lock(&port->lock);
6541bd671abSVishwanathapura, Niranjana 
6551bd671abSVishwanathapura, Niranjana 	switch (mad_wc->recv_buf.mad->mad_hdr.method) {
6561bd671abSVishwanathapura, Niranjana 	case IB_MGMT_METHOD_GET:
6571bd671abSVishwanathapura, Niranjana 		vema_get(port, (struct opa_vnic_vema_mad *)mad_wc->recv_buf.mad,
6581bd671abSVishwanathapura, Niranjana 			 vema_mad);
6591bd671abSVishwanathapura, Niranjana 		break;
6601bd671abSVishwanathapura, Niranjana 	case IB_MGMT_METHOD_SET:
6611bd671abSVishwanathapura, Niranjana 		vema_set(port, (struct opa_vnic_vema_mad *)mad_wc->recv_buf.mad,
6621bd671abSVishwanathapura, Niranjana 			 vema_mad);
6631bd671abSVishwanathapura, Niranjana 		break;
6641bd671abSVishwanathapura, Niranjana 	default:
6651bd671abSVishwanathapura, Niranjana 		vema_mad->mad_hdr.status = OPA_VNIC_UNSUP_ATTR;
6661bd671abSVishwanathapura, Niranjana 		break;
6671bd671abSVishwanathapura, Niranjana 	}
6681bd671abSVishwanathapura, Niranjana 	mutex_unlock(&port->lock);
6691bd671abSVishwanathapura, Niranjana 
6701bd671abSVishwanathapura, Niranjana 	if (!ib_post_send_mad(rsp, NULL)) {
6711bd671abSVishwanathapura, Niranjana 		/*
6721bd671abSVishwanathapura, Niranjana 		 * with post send successful ah and send mad
6731bd671abSVishwanathapura, Niranjana 		 * will be destroyed in send handler
6741bd671abSVishwanathapura, Niranjana 		 */
6751bd671abSVishwanathapura, Niranjana 		goto free_recv_mad;
6761bd671abSVishwanathapura, Niranjana 	}
6771bd671abSVishwanathapura, Niranjana 
6781bd671abSVishwanathapura, Niranjana 	ib_free_send_mad(rsp);
6791bd671abSVishwanathapura, Niranjana 
6801bd671abSVishwanathapura, Niranjana err_rsp:
6812553ba21SGal Pressman 	rdma_destroy_ah(ah, RDMA_DESTROY_AH_SLEEPABLE);
6821bd671abSVishwanathapura, Niranjana free_recv_mad:
6831bd671abSVishwanathapura, Niranjana 	ib_free_recv_mad(mad_wc);
6841bd671abSVishwanathapura, Niranjana }
6851bd671abSVishwanathapura, Niranjana 
6861bd671abSVishwanathapura, Niranjana /**
6871bd671abSVishwanathapura, Niranjana  * vema_get_port -- Gets the opa_vnic_vema_port
6881bd671abSVishwanathapura, Niranjana  * @cport: pointer to control dev
6891bd671abSVishwanathapura, Niranjana  * @port_num: Port number
6901bd671abSVishwanathapura, Niranjana  *
6911bd671abSVishwanathapura, Niranjana  * This function loops through the ports and returns
6921bd671abSVishwanathapura, Niranjana  * the opa_vnic_vema port structure that is associated
6931bd671abSVishwanathapura, Niranjana  * with the OPA port number
6941bd671abSVishwanathapura, Niranjana  *
6951bd671abSVishwanathapura, Niranjana  * Return: ptr to requested opa_vnic_vema_port strucure
6961bd671abSVishwanathapura, Niranjana  *         if success, NULL if not
6971bd671abSVishwanathapura, Niranjana  */
6981bd671abSVishwanathapura, Niranjana static struct opa_vnic_vema_port *
vema_get_port(struct opa_vnic_ctrl_port * cport,u8 port_num)6991bd671abSVishwanathapura, Niranjana vema_get_port(struct opa_vnic_ctrl_port *cport, u8 port_num)
7001bd671abSVishwanathapura, Niranjana {
7011bd671abSVishwanathapura, Niranjana 	struct opa_vnic_vema_port *port = (void *)cport + sizeof(*cport);
7021bd671abSVishwanathapura, Niranjana 
7031bd671abSVishwanathapura, Niranjana 	if (port_num > cport->num_ports)
7041bd671abSVishwanathapura, Niranjana 		return NULL;
7051bd671abSVishwanathapura, Niranjana 
7061bd671abSVishwanathapura, Niranjana 	return port + (port_num - 1);
7071bd671abSVishwanathapura, Niranjana }
7081bd671abSVishwanathapura, Niranjana 
7091bd671abSVishwanathapura, Niranjana /**
7101bd671abSVishwanathapura, Niranjana  * opa_vnic_vema_send_trap -- This function sends a trap to the EM
711cb8d0942SRandy Dunlap  * @adapter: pointer to vnic adapter
7121bd671abSVishwanathapura, Niranjana  * @data: pointer to trap data filled by calling function
7131bd671abSVishwanathapura, Niranjana  * @lid:  issuers lid (encap_slid from vesw_port_info)
7141bd671abSVishwanathapura, Niranjana  *
7151bd671abSVishwanathapura, Niranjana  * This function is called from the VNIC driver to send a trap if there
7161bd671abSVishwanathapura, Niranjana  * is somethng the EM should be notified about. These events currently
7171bd671abSVishwanathapura, Niranjana  * are
7181bd671abSVishwanathapura, Niranjana  * 1) UNICAST INTERFACE MACADDRESS changes
7191bd671abSVishwanathapura, Niranjana  * 2) MULTICAST INTERFACE MACADDRESS changes
7201bd671abSVishwanathapura, Niranjana  * 3) ETHERNET LINK STATUS changes
7211bd671abSVishwanathapura, Niranjana  * While allocating the send mad the remote site qpn used is 1
7221bd671abSVishwanathapura, Niranjana  * as this is the well known QP.
7231bd671abSVishwanathapura, Niranjana  *
7241bd671abSVishwanathapura, Niranjana  */
opa_vnic_vema_send_trap(struct opa_vnic_adapter * adapter,struct __opa_veswport_trap * data,u32 lid)7251bd671abSVishwanathapura, Niranjana void opa_vnic_vema_send_trap(struct opa_vnic_adapter *adapter,
7261bd671abSVishwanathapura, Niranjana 			     struct __opa_veswport_trap *data, u32 lid)
7271bd671abSVishwanathapura, Niranjana {
7281bd671abSVishwanathapura, Niranjana 	struct opa_vnic_ctrl_port *cport = adapter->cport;
7291bd671abSVishwanathapura, Niranjana 	struct ib_mad_send_buf *send_buf;
7301bd671abSVishwanathapura, Niranjana 	struct opa_vnic_vema_port *port;
7311bd671abSVishwanathapura, Niranjana 	struct ib_device *ibp;
7321bd671abSVishwanathapura, Niranjana 	struct opa_vnic_vema_mad_trap *trap_mad;
7331bd671abSVishwanathapura, Niranjana 	struct opa_class_port_info *class;
73490898850SDasaratharaman Chandramouli 	struct rdma_ah_attr ah_attr;
7351bd671abSVishwanathapura, Niranjana 	struct ib_ah *ah;
7361bd671abSVishwanathapura, Niranjana 	struct opa_veswport_trap *trap;
7371bd671abSVishwanathapura, Niranjana 	u32 trap_lid;
7381bd671abSVishwanathapura, Niranjana 	u16 pkey_idx;
7391bd671abSVishwanathapura, Niranjana 
7401bd671abSVishwanathapura, Niranjana 	if (!cport)
7411bd671abSVishwanathapura, Niranjana 		goto err_exit;
7421bd671abSVishwanathapura, Niranjana 	ibp = cport->ibdev;
7431bd671abSVishwanathapura, Niranjana 	port = vema_get_port(cport, data->opaportnum);
7441bd671abSVishwanathapura, Niranjana 	if (!port || !port->mad_agent)
7451bd671abSVishwanathapura, Niranjana 		goto err_exit;
7461bd671abSVishwanathapura, Niranjana 
7471bd671abSVishwanathapura, Niranjana 	if (time_before(jiffies, adapter->trap_timeout)) {
7481bd671abSVishwanathapura, Niranjana 		if (adapter->trap_count == OPA_VNIC_TRAP_BURST_LIMIT) {
7491bd671abSVishwanathapura, Niranjana 			v_warn("Trap rate exceeded\n");
7501bd671abSVishwanathapura, Niranjana 			goto err_exit;
7511bd671abSVishwanathapura, Niranjana 		} else {
7521bd671abSVishwanathapura, Niranjana 			adapter->trap_count++;
7531bd671abSVishwanathapura, Niranjana 		}
7541bd671abSVishwanathapura, Niranjana 	} else {
7551bd671abSVishwanathapura, Niranjana 		adapter->trap_count = 0;
7561bd671abSVishwanathapura, Niranjana 	}
7571bd671abSVishwanathapura, Niranjana 
7581bd671abSVishwanathapura, Niranjana 	class = &port->class_port_info;
7591bd671abSVishwanathapura, Niranjana 	/* Set up address handle */
7601bd671abSVishwanathapura, Niranjana 	memset(&ah_attr, 0, sizeof(ah_attr));
76144c58487SDasaratharaman Chandramouli 	ah_attr.type = rdma_ah_find_type(ibp, port->port_num);
762d8966fcdSDasaratharaman Chandramouli 	rdma_ah_set_sl(&ah_attr,
763d8966fcdSDasaratharaman Chandramouli 		       GET_TRAP_SL_FROM_CLASS_PORT_INFO(class->trap_sl_rsvd));
764d8966fcdSDasaratharaman Chandramouli 	rdma_ah_set_port_num(&ah_attr, port->port_num);
7651bd671abSVishwanathapura, Niranjana 	trap_lid = be32_to_cpu(class->trap_lid);
7661bd671abSVishwanathapura, Niranjana 	/*
7671bd671abSVishwanathapura, Niranjana 	 * check for trap lid validity, must not be zero
7681bd671abSVishwanathapura, Niranjana 	 * The trap sink could change after we fashion the MAD but since traps
7691bd671abSVishwanathapura, Niranjana 	 * are not guaranteed we won't use a lock as anyway the change will take
7701bd671abSVishwanathapura, Niranjana 	 * place even with locking.
7711bd671abSVishwanathapura, Niranjana 	 */
7721bd671abSVishwanathapura, Niranjana 	if (!trap_lid) {
7731bd671abSVishwanathapura, Niranjana 		c_err("%s: Invalid dlid\n", __func__);
7741bd671abSVishwanathapura, Niranjana 		goto err_exit;
7751bd671abSVishwanathapura, Niranjana 	}
7761bd671abSVishwanathapura, Niranjana 
777d8966fcdSDasaratharaman Chandramouli 	rdma_ah_set_dlid(&ah_attr, trap_lid);
778b090c4e3SGal Pressman 	ah = rdma_create_ah(port->mad_agent->qp->pd, &ah_attr, 0);
7791bd671abSVishwanathapura, Niranjana 	if (IS_ERR(ah)) {
7801bd671abSVishwanathapura, Niranjana 		c_err("%s:Couldn't create new AH = %p\n", __func__, ah);
7811bd671abSVishwanathapura, Niranjana 		c_err("%s:dlid = %d, sl = %d, port = %d\n", __func__,
782d8966fcdSDasaratharaman Chandramouli 		      rdma_ah_get_dlid(&ah_attr), rdma_ah_get_sl(&ah_attr),
783d8966fcdSDasaratharaman Chandramouli 		      rdma_ah_get_port_num(&ah_attr));
7841bd671abSVishwanathapura, Niranjana 		goto err_exit;
7851bd671abSVishwanathapura, Niranjana 	}
7861bd671abSVishwanathapura, Niranjana 
7871bd671abSVishwanathapura, Niranjana 	if (ib_find_pkey(ibp, data->opaportnum, IB_DEFAULT_PKEY_FULL,
7881bd671abSVishwanathapura, Niranjana 			 &pkey_idx) < 0) {
7891bd671abSVishwanathapura, Niranjana 		c_err("%s:full key not found, defaulting to partial\n",
7901bd671abSVishwanathapura, Niranjana 		      __func__);
7911bd671abSVishwanathapura, Niranjana 		if (ib_find_pkey(ibp, data->opaportnum, IB_DEFAULT_PKEY_PARTIAL,
7921bd671abSVishwanathapura, Niranjana 				 &pkey_idx) < 0)
7931bd671abSVishwanathapura, Niranjana 			pkey_idx = 1;
7941bd671abSVishwanathapura, Niranjana 	}
7951bd671abSVishwanathapura, Niranjana 
7961bd671abSVishwanathapura, Niranjana 	send_buf = ib_create_send_mad(port->mad_agent, 1, pkey_idx, 0,
7971bd671abSVishwanathapura, Niranjana 				      IB_MGMT_VENDOR_HDR, IB_MGMT_MAD_DATA,
7980568c464SVishwanathapura, Niranjana 				      GFP_ATOMIC, OPA_MGMT_BASE_VERSION);
7991bd671abSVishwanathapura, Niranjana 	if (IS_ERR(send_buf)) {
8001bd671abSVishwanathapura, Niranjana 		c_err("%s:Couldn't allocate send buf\n", __func__);
8011bd671abSVishwanathapura, Niranjana 		goto err_sndbuf;
8021bd671abSVishwanathapura, Niranjana 	}
8031bd671abSVishwanathapura, Niranjana 
8041bd671abSVishwanathapura, Niranjana 	send_buf->ah = ah;
8051bd671abSVishwanathapura, Niranjana 
8061bd671abSVishwanathapura, Niranjana 	/* Set up common MAD hdr */
8071bd671abSVishwanathapura, Niranjana 	trap_mad = send_buf->mad;
8081bd671abSVishwanathapura, Niranjana 	trap_mad->mad_hdr.base_version = OPA_MGMT_BASE_VERSION;
8091bd671abSVishwanathapura, Niranjana 	trap_mad->mad_hdr.mgmt_class = OPA_MGMT_CLASS_INTEL_EMA;
8101bd671abSVishwanathapura, Niranjana 	trap_mad->mad_hdr.class_version = OPA_EMA_CLASS_VERSION;
8111bd671abSVishwanathapura, Niranjana 	trap_mad->mad_hdr.method = IB_MGMT_METHOD_TRAP;
8121bd671abSVishwanathapura, Niranjana 	port->tid++;
8131bd671abSVishwanathapura, Niranjana 	trap_mad->mad_hdr.tid = cpu_to_be64(port->tid);
8141bd671abSVishwanathapura, Niranjana 	trap_mad->mad_hdr.attr_id = IB_SMP_ATTR_NOTICE;
8151bd671abSVishwanathapura, Niranjana 
8161bd671abSVishwanathapura, Niranjana 	/* Set up vendor OUI */
8171bd671abSVishwanathapura, Niranjana 	trap_mad->oui[0] = INTEL_OUI_1;
8181bd671abSVishwanathapura, Niranjana 	trap_mad->oui[1] = INTEL_OUI_2;
8191bd671abSVishwanathapura, Niranjana 	trap_mad->oui[2] = INTEL_OUI_3;
8201bd671abSVishwanathapura, Niranjana 
8211bd671abSVishwanathapura, Niranjana 	/* Setup notice attribute portion */
8221bd671abSVishwanathapura, Niranjana 	trap_mad->notice.gen_type = OPA_INTEL_EMA_NOTICE_TYPE_INFO << 1;
8231bd671abSVishwanathapura, Niranjana 	trap_mad->notice.oui_1 = INTEL_OUI_1;
8241bd671abSVishwanathapura, Niranjana 	trap_mad->notice.oui_2 = INTEL_OUI_2;
8251bd671abSVishwanathapura, Niranjana 	trap_mad->notice.oui_3 = INTEL_OUI_3;
8261bd671abSVishwanathapura, Niranjana 	trap_mad->notice.issuer_lid = cpu_to_be32(lid);
8271bd671abSVishwanathapura, Niranjana 
8281bd671abSVishwanathapura, Niranjana 	/* copy the actual trap data */
8291bd671abSVishwanathapura, Niranjana 	trap = (struct opa_veswport_trap *)trap_mad->notice.raw_data;
8301bd671abSVishwanathapura, Niranjana 	trap->fabric_id = cpu_to_be16(data->fabric_id);
8311bd671abSVishwanathapura, Niranjana 	trap->veswid = cpu_to_be16(data->veswid);
8321bd671abSVishwanathapura, Niranjana 	trap->veswportnum = cpu_to_be32(data->veswportnum);
8331bd671abSVishwanathapura, Niranjana 	trap->opaportnum = cpu_to_be16(data->opaportnum);
8341bd671abSVishwanathapura, Niranjana 	trap->veswportindex = data->veswportindex;
8351bd671abSVishwanathapura, Niranjana 	trap->opcode = data->opcode;
8361bd671abSVishwanathapura, Niranjana 
8371bd671abSVishwanathapura, Niranjana 	/* If successful send set up rate limit timeout else bail */
8381bd671abSVishwanathapura, Niranjana 	if (ib_post_send_mad(send_buf, NULL)) {
8391bd671abSVishwanathapura, Niranjana 		ib_free_send_mad(send_buf);
8401bd671abSVishwanathapura, Niranjana 	} else {
8411bd671abSVishwanathapura, Niranjana 		if (adapter->trap_count)
8421bd671abSVishwanathapura, Niranjana 			return;
8431bd671abSVishwanathapura, Niranjana 		adapter->trap_timeout = jiffies +
8441bd671abSVishwanathapura, Niranjana 					usecs_to_jiffies(OPA_VNIC_TRAP_TIMEOUT);
8451bd671abSVishwanathapura, Niranjana 		return;
8461bd671abSVishwanathapura, Niranjana 	}
8471bd671abSVishwanathapura, Niranjana 
8481bd671abSVishwanathapura, Niranjana err_sndbuf:
8492553ba21SGal Pressman 	rdma_destroy_ah(ah, 0);
8501bd671abSVishwanathapura, Niranjana err_exit:
8511bd671abSVishwanathapura, Niranjana 	v_err("Aborting trap\n");
8521bd671abSVishwanathapura, Niranjana }
8531bd671abSVishwanathapura, Niranjana 
opa_vnic_event(struct ib_event_handler * handler,struct ib_event * record)8541bd671abSVishwanathapura, Niranjana static void opa_vnic_event(struct ib_event_handler *handler,
8551bd671abSVishwanathapura, Niranjana 			   struct ib_event *record)
8561bd671abSVishwanathapura, Niranjana {
8571bd671abSVishwanathapura, Niranjana 	struct opa_vnic_vema_port *port =
8581bd671abSVishwanathapura, Niranjana 		container_of(handler, struct opa_vnic_vema_port, event_handler);
8591bd671abSVishwanathapura, Niranjana 	struct opa_vnic_ctrl_port *cport = port->cport;
860fae7a699SMatthew Wilcox 	struct opa_vnic_adapter *adapter;
861fae7a699SMatthew Wilcox 	unsigned long index;
8621bd671abSVishwanathapura, Niranjana 
8631bd671abSVishwanathapura, Niranjana 	if (record->element.port_num != port->port_num)
8641bd671abSVishwanathapura, Niranjana 		return;
8651bd671abSVishwanathapura, Niranjana 
8661bd671abSVishwanathapura, Niranjana 	c_dbg("OPA_VNIC received event %d on device %s port %d\n",
8676c854111SJason Gunthorpe 	      record->event, dev_name(&record->device->dev),
8686c854111SJason Gunthorpe 	      record->element.port_num);
8691bd671abSVishwanathapura, Niranjana 
8704d2e11d4SColin Ian King 	if (record->event != IB_EVENT_PORT_ERR &&
871fae7a699SMatthew Wilcox 	    record->event != IB_EVENT_PORT_ACTIVE)
872fae7a699SMatthew Wilcox 		return;
873fae7a699SMatthew Wilcox 
874fae7a699SMatthew Wilcox 	xa_for_each(&port->vports, index, adapter) {
8751bd671abSVishwanathapura, Niranjana 		if (record->event == IB_EVENT_PORT_ACTIVE)
876fae7a699SMatthew Wilcox 			netif_carrier_on(adapter->netdev);
877fae7a699SMatthew Wilcox 		else
878fae7a699SMatthew Wilcox 			netif_carrier_off(adapter->netdev);
879fae7a699SMatthew Wilcox 	}
8801bd671abSVishwanathapura, Niranjana }
8811bd671abSVishwanathapura, Niranjana 
8821bd671abSVishwanathapura, Niranjana /**
8831bd671abSVishwanathapura, Niranjana  * vema_unregister -- Unregisters agent
8841bd671abSVishwanathapura, Niranjana  * @cport: pointer to control port
8851bd671abSVishwanathapura, Niranjana  *
8861bd671abSVishwanathapura, Niranjana  * This deletes the registration by VEMA for MADs
8871bd671abSVishwanathapura, Niranjana  */
vema_unregister(struct opa_vnic_ctrl_port * cport)8881bd671abSVishwanathapura, Niranjana static void vema_unregister(struct opa_vnic_ctrl_port *cport)
8891bd671abSVishwanathapura, Niranjana {
890fae7a699SMatthew Wilcox 	struct opa_vnic_adapter *adapter;
891fae7a699SMatthew Wilcox 	unsigned long index;
8921bd671abSVishwanathapura, Niranjana 	int i;
8931bd671abSVishwanathapura, Niranjana 
8941bd671abSVishwanathapura, Niranjana 	for (i = 1; i <= cport->num_ports; i++) {
8951bd671abSVishwanathapura, Niranjana 		struct opa_vnic_vema_port *port = vema_get_port(cport, i);
8961bd671abSVishwanathapura, Niranjana 
8971bd671abSVishwanathapura, Niranjana 		if (!port->mad_agent)
8981bd671abSVishwanathapura, Niranjana 			continue;
8991bd671abSVishwanathapura, Niranjana 
9001bd671abSVishwanathapura, Niranjana 		/* Lock ensures no MAD is being processed */
9011bd671abSVishwanathapura, Niranjana 		mutex_lock(&port->lock);
902fae7a699SMatthew Wilcox 		xa_for_each(&port->vports, index, adapter)
903fae7a699SMatthew Wilcox 			opa_vnic_rem_netdev(adapter);
9041bd671abSVishwanathapura, Niranjana 		mutex_unlock(&port->lock);
9051bd671abSVishwanathapura, Niranjana 
9061bd671abSVishwanathapura, Niranjana 		ib_unregister_mad_agent(port->mad_agent);
9071bd671abSVishwanathapura, Niranjana 		port->mad_agent = NULL;
9081bd671abSVishwanathapura, Niranjana 		mutex_destroy(&port->lock);
909fae7a699SMatthew Wilcox 		xa_destroy(&port->vports);
9101bd671abSVishwanathapura, Niranjana 		ib_unregister_event_handler(&port->event_handler);
9111bd671abSVishwanathapura, Niranjana 	}
9121bd671abSVishwanathapura, Niranjana }
9131bd671abSVishwanathapura, Niranjana 
9141bd671abSVishwanathapura, Niranjana /**
9151bd671abSVishwanathapura, Niranjana  * vema_register -- Registers agent
9161bd671abSVishwanathapura, Niranjana  * @cport: pointer to control port
9171bd671abSVishwanathapura, Niranjana  *
9181bd671abSVishwanathapura, Niranjana  * This function registers the handlers for the VEMA MADs
9191bd671abSVishwanathapura, Niranjana  *
9201bd671abSVishwanathapura, Niranjana  * Return: returns 0 on success. non zero otherwise
9211bd671abSVishwanathapura, Niranjana  */
vema_register(struct opa_vnic_ctrl_port * cport)9221bd671abSVishwanathapura, Niranjana static int vema_register(struct opa_vnic_ctrl_port *cport)
9231bd671abSVishwanathapura, Niranjana {
9241bd671abSVishwanathapura, Niranjana 	struct ib_mad_reg_req reg_req = {
9251bd671abSVishwanathapura, Niranjana 		.mgmt_class = OPA_MGMT_CLASS_INTEL_EMA,
9261bd671abSVishwanathapura, Niranjana 		.mgmt_class_version = OPA_MGMT_BASE_VERSION,
9271bd671abSVishwanathapura, Niranjana 		.oui = { INTEL_OUI_1, INTEL_OUI_2, INTEL_OUI_3 }
9281bd671abSVishwanathapura, Niranjana 	};
9291bd671abSVishwanathapura, Niranjana 	int i;
9301bd671abSVishwanathapura, Niranjana 
9311bd671abSVishwanathapura, Niranjana 	set_bit(IB_MGMT_METHOD_GET, reg_req.method_mask);
9321bd671abSVishwanathapura, Niranjana 	set_bit(IB_MGMT_METHOD_SET, reg_req.method_mask);
9331bd671abSVishwanathapura, Niranjana 
9341bd671abSVishwanathapura, Niranjana 	/* register ib event handler and mad agent for each port on dev */
9351bd671abSVishwanathapura, Niranjana 	for (i = 1; i <= cport->num_ports; i++) {
9361bd671abSVishwanathapura, Niranjana 		struct opa_vnic_vema_port *port = vema_get_port(cport, i);
9371bd671abSVishwanathapura, Niranjana 		int ret;
9381bd671abSVishwanathapura, Niranjana 
9391bd671abSVishwanathapura, Niranjana 		port->cport = cport;
9401bd671abSVishwanathapura, Niranjana 		port->port_num = i;
9411bd671abSVishwanathapura, Niranjana 
9421bd671abSVishwanathapura, Niranjana 		INIT_IB_EVENT_HANDLER(&port->event_handler,
9431bd671abSVishwanathapura, Niranjana 				      cport->ibdev, opa_vnic_event);
944dcc9881eSLeon Romanovsky 		ib_register_event_handler(&port->event_handler);
9451bd671abSVishwanathapura, Niranjana 
946fae7a699SMatthew Wilcox 		xa_init(&port->vports);
9471bd671abSVishwanathapura, Niranjana 		mutex_init(&port->lock);
9481bd671abSVishwanathapura, Niranjana 		port->mad_agent = ib_register_mad_agent(cport->ibdev, i,
9491bd671abSVishwanathapura, Niranjana 							IB_QPT_GSI, &reg_req,
9501bd671abSVishwanathapura, Niranjana 							IB_MGMT_RMPP_VERSION,
9511bd671abSVishwanathapura, Niranjana 							vema_send, vema_recv,
9521bd671abSVishwanathapura, Niranjana 							port, 0);
9531bd671abSVishwanathapura, Niranjana 		if (IS_ERR(port->mad_agent)) {
9541bd671abSVishwanathapura, Niranjana 			ret = PTR_ERR(port->mad_agent);
9551bd671abSVishwanathapura, Niranjana 			port->mad_agent = NULL;
9561bd671abSVishwanathapura, Niranjana 			mutex_destroy(&port->lock);
9571bd671abSVishwanathapura, Niranjana 			vema_unregister(cport);
9581bd671abSVishwanathapura, Niranjana 			return ret;
9591bd671abSVishwanathapura, Niranjana 		}
9601bd671abSVishwanathapura, Niranjana 	}
9611bd671abSVishwanathapura, Niranjana 
9621bd671abSVishwanathapura, Niranjana 	return 0;
9631bd671abSVishwanathapura, Niranjana }
9641bd671abSVishwanathapura, Niranjana 
9651bd671abSVishwanathapura, Niranjana /**
966cb49366fSVishwanathapura, Niranjana  * opa_vnic_ctrl_config_dev -- This function sends a trap to the EM
967cb49366fSVishwanathapura, Niranjana  * by way of ib_modify_port to indicate support for ethernet on the
968cb49366fSVishwanathapura, Niranjana  * fabric.
969cb49366fSVishwanathapura, Niranjana  * @cport: pointer to control port
970cb49366fSVishwanathapura, Niranjana  * @en: enable or disable ethernet on fabric support
971cb49366fSVishwanathapura, Niranjana  */
opa_vnic_ctrl_config_dev(struct opa_vnic_ctrl_port * cport,bool en)972cb49366fSVishwanathapura, Niranjana static void opa_vnic_ctrl_config_dev(struct opa_vnic_ctrl_port *cport, bool en)
973cb49366fSVishwanathapura, Niranjana {
974cb49366fSVishwanathapura, Niranjana 	struct ib_port_modify pm = { 0 };
975cb49366fSVishwanathapura, Niranjana 	int i;
976cb49366fSVishwanathapura, Niranjana 
977cb49366fSVishwanathapura, Niranjana 	if (en)
978cb49366fSVishwanathapura, Niranjana 		pm.set_port_cap_mask = OPA_CAP_MASK3_IsEthOnFabricSupported;
979cb49366fSVishwanathapura, Niranjana 	else
980cb49366fSVishwanathapura, Niranjana 		pm.clr_port_cap_mask = OPA_CAP_MASK3_IsEthOnFabricSupported;
981cb49366fSVishwanathapura, Niranjana 
982cb49366fSVishwanathapura, Niranjana 	for (i = 1; i <= cport->num_ports; i++)
983cb49366fSVishwanathapura, Niranjana 		ib_modify_port(cport->ibdev, i, IB_PORT_OPA_MASK_CHG, &pm);
984cb49366fSVishwanathapura, Niranjana }
985cb49366fSVishwanathapura, Niranjana 
986cb49366fSVishwanathapura, Niranjana /**
9871bd671abSVishwanathapura, Niranjana  * opa_vnic_vema_add_one -- Handle new ib device
9881bd671abSVishwanathapura, Niranjana  * @device: ib device pointer
9891bd671abSVishwanathapura, Niranjana  *
9901bd671abSVishwanathapura, Niranjana  * Allocate the vnic control port and initialize it.
9911bd671abSVishwanathapura, Niranjana  */
opa_vnic_vema_add_one(struct ib_device * device)99211a0ae4cSJason Gunthorpe static int opa_vnic_vema_add_one(struct ib_device *device)
9931bd671abSVishwanathapura, Niranjana {
9941bd671abSVishwanathapura, Niranjana 	struct opa_vnic_ctrl_port *cport;
9951bd671abSVishwanathapura, Niranjana 	int rc, size = sizeof(*cport);
9961bd671abSVishwanathapura, Niranjana 
9971bd671abSVishwanathapura, Niranjana 	if (!rdma_cap_opa_vnic(device))
99811a0ae4cSJason Gunthorpe 		return -EOPNOTSUPP;
9991bd671abSVishwanathapura, Niranjana 
10001bd671abSVishwanathapura, Niranjana 	size += device->phys_port_cnt * sizeof(struct opa_vnic_vema_port);
10011bd671abSVishwanathapura, Niranjana 	cport = kzalloc(size, GFP_KERNEL);
10021bd671abSVishwanathapura, Niranjana 	if (!cport)
100311a0ae4cSJason Gunthorpe 		return -ENOMEM;
10041bd671abSVishwanathapura, Niranjana 
10051bd671abSVishwanathapura, Niranjana 	cport->num_ports = device->phys_port_cnt;
10061bd671abSVishwanathapura, Niranjana 	cport->ibdev = device;
10071bd671abSVishwanathapura, Niranjana 
10081bd671abSVishwanathapura, Niranjana 	/* Initialize opa vnic management agent (vema) */
10091bd671abSVishwanathapura, Niranjana 	rc = vema_register(cport);
10101bd671abSVishwanathapura, Niranjana 	if (!rc)
10111bd671abSVishwanathapura, Niranjana 		c_info("VNIC client initialized\n");
10121bd671abSVishwanathapura, Niranjana 
10131bd671abSVishwanathapura, Niranjana 	ib_set_client_data(device, &opa_vnic_client, cport);
1014cb49366fSVishwanathapura, Niranjana 	opa_vnic_ctrl_config_dev(cport, true);
101511a0ae4cSJason Gunthorpe 	return 0;
10161bd671abSVishwanathapura, Niranjana }
10171bd671abSVishwanathapura, Niranjana 
10181bd671abSVishwanathapura, Niranjana /**
10191bd671abSVishwanathapura, Niranjana  * opa_vnic_vema_rem_one -- Handle ib device removal
10201bd671abSVishwanathapura, Niranjana  * @device: ib device pointer
10211bd671abSVishwanathapura, Niranjana  * @client_data: ib client data
10221bd671abSVishwanathapura, Niranjana  *
10231bd671abSVishwanathapura, Niranjana  * Uninitialize and free the vnic control port.
10241bd671abSVishwanathapura, Niranjana  */
opa_vnic_vema_rem_one(struct ib_device * device,void * client_data)10251bd671abSVishwanathapura, Niranjana static void opa_vnic_vema_rem_one(struct ib_device *device,
10261bd671abSVishwanathapura, Niranjana 				  void *client_data)
10271bd671abSVishwanathapura, Niranjana {
10281bd671abSVishwanathapura, Niranjana 	struct opa_vnic_ctrl_port *cport = client_data;
10291bd671abSVishwanathapura, Niranjana 
10301bd671abSVishwanathapura, Niranjana 	c_info("removing VNIC client\n");
1031cb49366fSVishwanathapura, Niranjana 	opa_vnic_ctrl_config_dev(cport, false);
10321bd671abSVishwanathapura, Niranjana 	vema_unregister(cport);
10331bd671abSVishwanathapura, Niranjana 	kfree(cport);
10341bd671abSVishwanathapura, Niranjana }
10351bd671abSVishwanathapura, Niranjana 
opa_vnic_init(void)10361bd671abSVishwanathapura, Niranjana static int __init opa_vnic_init(void)
10371bd671abSVishwanathapura, Niranjana {
10381bd671abSVishwanathapura, Niranjana 	int rc;
10391bd671abSVishwanathapura, Niranjana 
10401bd671abSVishwanathapura, Niranjana 	rc = ib_register_client(&opa_vnic_client);
10411bd671abSVishwanathapura, Niranjana 	if (rc)
10421bd671abSVishwanathapura, Niranjana 		pr_err("VNIC driver register failed %d\n", rc);
10431bd671abSVishwanathapura, Niranjana 
10441bd671abSVishwanathapura, Niranjana 	return rc;
10451bd671abSVishwanathapura, Niranjana }
10461bd671abSVishwanathapura, Niranjana module_init(opa_vnic_init);
10471bd671abSVishwanathapura, Niranjana 
opa_vnic_deinit(void)10481bd671abSVishwanathapura, Niranjana static void opa_vnic_deinit(void)
10491bd671abSVishwanathapura, Niranjana {
10501bd671abSVishwanathapura, Niranjana 	ib_unregister_client(&opa_vnic_client);
10511bd671abSVishwanathapura, Niranjana }
10521bd671abSVishwanathapura, Niranjana module_exit(opa_vnic_deinit);
10531bd671abSVishwanathapura, Niranjana 
10541bd671abSVishwanathapura, Niranjana MODULE_LICENSE("Dual BSD/GPL");
1055*4892298cSScott Breyer MODULE_AUTHOR("Cornelis Networks");
1056*4892298cSScott Breyer MODULE_DESCRIPTION("Cornelis OPX Virtual Network driver");
1057