12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076 |
- /*
- * Copyright(c) 2017 Intel Corporation.
- *
- * This file is provided under a dual BSD/GPLv2 license. When using or
- * redistributing this file, you may do so under either license.
- *
- * GPL LICENSE SUMMARY
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * BSD LICENSE
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * - Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- * - Neither the name of Intel Corporation nor the names of its
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
- /*
- * This file contains OPA Virtual Network Interface Controller (VNIC)
- * Ethernet Management Agent (EMA) driver
- */
- #include <linux/module.h>
- #include <rdma/ib_addr.h>
- #include <rdma/ib_verbs.h>
- #include <rdma/opa_smi.h>
- #include <rdma/opa_port_info.h>
- #include "opa_vnic_internal.h"
- #define DRV_VERSION "1.0"
- char opa_vnic_driver_name[] = "opa_vnic";
- const char opa_vnic_driver_version[] = DRV_VERSION;
- /*
- * The trap service level is kept in bits 3 to 7 in the trap_sl_rsvd
- * field in the class port info MAD.
- */
- #define GET_TRAP_SL_FROM_CLASS_PORT_INFO(x) (((x) >> 3) & 0x1f)
- /* Cap trap bursts to a reasonable limit good for normal cases */
- #define OPA_VNIC_TRAP_BURST_LIMIT 4
- /*
- * VNIC trap limit timeout.
- * Inverse of cap2_mask response time out (1.0737 secs) = 0.9
- * secs approx IB spec 13.4.6.2.1 PortInfoSubnetTimeout and
- * 13.4.9 Traps.
- */
- #define OPA_VNIC_TRAP_TIMEOUT ((4096 * (1UL << 18)) / 1000)
- #define OPA_VNIC_UNSUP_ATTR \
- cpu_to_be16(IB_MGMT_MAD_STATUS_UNSUPPORTED_METHOD_ATTRIB)
- #define OPA_VNIC_INVAL_ATTR \
- cpu_to_be16(IB_MGMT_MAD_STATUS_INVALID_ATTRIB_VALUE)
- #define OPA_VNIC_CLASS_CAP_TRAP 0x1
- /* Maximum number of VNIC ports supported */
- #define OPA_VNIC_MAX_NUM_VPORT 255
- /**
- * struct opa_vnic_vema_port -- VNIC VEMA port details
- * @cport: pointer to port
- * @mad_agent: pointer to mad agent for port
- * @class_port_info: Class port info information.
- * @tid: Transaction id
- * @port_num: OPA port number
- * @vport_idr: vnic ports idr
- * @event_handler: ib event handler
- * @lock: adapter interface lock
- */
- struct opa_vnic_vema_port {
- struct opa_vnic_ctrl_port *cport;
- struct ib_mad_agent *mad_agent;
- struct opa_class_port_info class_port_info;
- u64 tid;
- u8 port_num;
- struct idr vport_idr;
- struct ib_event_handler event_handler;
- /* Lock to query/update network adapter */
- struct mutex lock;
- };
- static void opa_vnic_vema_add_one(struct ib_device *device);
- static void opa_vnic_vema_rem_one(struct ib_device *device,
- void *client_data);
- static struct ib_client opa_vnic_client = {
- .name = opa_vnic_driver_name,
- .add = opa_vnic_vema_add_one,
- .remove = opa_vnic_vema_rem_one,
- };
- /**
- * vema_get_vport_num -- Get the vnic from the mad
- * @recvd_mad: Received mad
- *
- * Return: returns value of the vnic port number
- */
- static inline u8 vema_get_vport_num(struct opa_vnic_vema_mad *recvd_mad)
- {
- return be32_to_cpu(recvd_mad->mad_hdr.attr_mod) & 0xff;
- }
- /**
- * vema_get_vport_adapter -- Get vnic port adapter from recvd mad
- * @recvd_mad: received mad
- * @port: ptr to port struct on which MAD was recvd
- *
- * Return: vnic adapter
- */
- static inline struct opa_vnic_adapter *
- vema_get_vport_adapter(struct opa_vnic_vema_mad *recvd_mad,
- struct opa_vnic_vema_port *port)
- {
- u8 vport_num = vema_get_vport_num(recvd_mad);
- return idr_find(&port->vport_idr, vport_num);
- }
- /**
- * vema_mac_tbl_req_ok -- Check if mac request has correct values
- * @mac_tbl: mac table
- *
- * This function checks for the validity of the offset and number of
- * entries required.
- *
- * Return: true if offset and num_entries are valid
- */
- static inline bool vema_mac_tbl_req_ok(struct opa_veswport_mactable *mac_tbl)
- {
- u16 offset, num_entries;
- u16 req_entries = ((OPA_VNIC_EMA_DATA - sizeof(*mac_tbl)) /
- sizeof(mac_tbl->tbl_entries[0]));
- offset = be16_to_cpu(mac_tbl->offset);
- num_entries = be16_to_cpu(mac_tbl->num_entries);
- return ((num_entries <= req_entries) &&
- (offset + num_entries <= OPA_VNIC_MAC_TBL_MAX_ENTRIES));
- }
- /*
- * Return the power on default values in the port info structure
- * in big endian format as required by MAD.
- */
- static inline void vema_get_pod_values(struct opa_veswport_info *port_info)
- {
- memset(port_info, 0, sizeof(*port_info));
- port_info->vport.max_mac_tbl_ent =
- cpu_to_be16(OPA_VNIC_MAC_TBL_MAX_ENTRIES);
- port_info->vport.max_smac_ent =
- cpu_to_be16(OPA_VNIC_MAX_SMAC_LIMIT);
- port_info->vport.oper_state = OPA_VNIC_STATE_DROP_ALL;
- port_info->vport.config_state = OPA_VNIC_STATE_DROP_ALL;
- port_info->vesw.eth_mtu = cpu_to_be16(ETH_DATA_LEN);
- }
- /**
- * vema_add_vport -- Add a new vnic port
- * @port: ptr to opa_vnic_vema_port struct
- * @vport_num: vnic port number (to be added)
- *
- * Return a pointer to the vnic adapter structure
- */
- static struct opa_vnic_adapter *vema_add_vport(struct opa_vnic_vema_port *port,
- u8 vport_num)
- {
- struct opa_vnic_ctrl_port *cport = port->cport;
- struct opa_vnic_adapter *adapter;
- adapter = opa_vnic_add_netdev(cport->ibdev, port->port_num, vport_num);
- if (!IS_ERR(adapter)) {
- int rc;
- adapter->cport = cport;
- rc = idr_alloc(&port->vport_idr, adapter, vport_num,
- vport_num + 1, GFP_NOWAIT);
- if (rc < 0) {
- opa_vnic_rem_netdev(adapter);
- adapter = ERR_PTR(rc);
- }
- }
- return adapter;
- }
- /**
- * vema_get_class_port_info -- Get class info for port
- * @port: Port on whic MAD was received
- * @recvd_mad: pointer to the received mad
- * @rsp_mad: pointer to respose mad
- *
- * This function copies the latest class port info value set for the
- * port and stores it for generating traps
- */
- static void 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)
- {
- struct opa_class_port_info *port_info;
- port_info = (struct opa_class_port_info *)rsp_mad->data;
- memcpy(port_info, &port->class_port_info, sizeof(*port_info));
- port_info->base_version = OPA_MGMT_BASE_VERSION,
- port_info->class_version = OPA_EMA_CLASS_VERSION;
- /*
- * Set capability mask bit indicating agent generates traps,
- * and set the maximum number of VNIC ports supported.
- */
- port_info->cap_mask = cpu_to_be16((OPA_VNIC_CLASS_CAP_TRAP |
- (OPA_VNIC_MAX_NUM_VPORT << 8)));
- /*
- * Since a get routine is always sent by the EM first we
- * set the expected response time to
- * 4.096 usec * 2^18 == 1.0737 sec here.
- */
- port_info->cap_mask2_resp_time = cpu_to_be32(18);
- }
- /**
- * vema_set_class_port_info -- Get class info for port
- * @port: Port on whic MAD was received
- * @recvd_mad: pointer to the received mad
- * @rsp_mad: pointer to respose mad
- *
- * This function updates the port class info for the specific vnic
- * and sets up the response mad data
- */
- static void 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)
- {
- memcpy(&port->class_port_info, recvd_mad->data,
- sizeof(port->class_port_info));
- vema_get_class_port_info(port, recvd_mad, rsp_mad);
- }
- /**
- * vema_get_veswport_info -- Get veswport info
- * @port: source port on which MAD was received
- * @recvd_mad: pointer to the received mad
- * @rsp_mad: pointer to respose mad
- */
- static void vema_get_veswport_info(struct opa_vnic_vema_port *port,
- struct opa_vnic_vema_mad *recvd_mad,
- struct opa_vnic_vema_mad *rsp_mad)
- {
- struct opa_veswport_info *port_info =
- (struct opa_veswport_info *)rsp_mad->data;
- struct opa_vnic_adapter *adapter;
- adapter = vema_get_vport_adapter(recvd_mad, port);
- if (adapter) {
- memset(port_info, 0, sizeof(*port_info));
- opa_vnic_get_vesw_info(adapter, &port_info->vesw);
- opa_vnic_get_per_veswport_info(adapter,
- &port_info->vport);
- } else {
- vema_get_pod_values(port_info);
- }
- }
- /**
- * vema_set_veswport_info -- Set veswport info
- * @port: source port on which MAD was received
- * @recvd_mad: pointer to the received mad
- * @rsp_mad: pointer to respose mad
- *
- * This function gets the port class infor for vnic
- */
- static void vema_set_veswport_info(struct opa_vnic_vema_port *port,
- struct opa_vnic_vema_mad *recvd_mad,
- struct opa_vnic_vema_mad *rsp_mad)
- {
- struct opa_vnic_ctrl_port *cport = port->cport;
- struct opa_veswport_info *port_info;
- struct opa_vnic_adapter *adapter;
- u8 vport_num;
- vport_num = vema_get_vport_num(recvd_mad);
- adapter = vema_get_vport_adapter(recvd_mad, port);
- if (!adapter) {
- adapter = vema_add_vport(port, vport_num);
- if (IS_ERR(adapter)) {
- c_err("failed to add vport %d: %ld\n",
- vport_num, PTR_ERR(adapter));
- goto err_exit;
- }
- }
- port_info = (struct opa_veswport_info *)recvd_mad->data;
- opa_vnic_set_vesw_info(adapter, &port_info->vesw);
- opa_vnic_set_per_veswport_info(adapter, &port_info->vport);
- /* Process the new config settings */
- opa_vnic_process_vema_config(adapter);
- vema_get_veswport_info(port, recvd_mad, rsp_mad);
- return;
- err_exit:
- rsp_mad->mad_hdr.status = OPA_VNIC_INVAL_ATTR;
- }
- /**
- * vema_get_mac_entries -- Get MAC entries in VNIC MAC table
- * @port: source port on which MAD was received
- * @recvd_mad: pointer to the received mad
- * @rsp_mad: pointer to respose mad
- *
- * This function gets the MAC entries that are programmed into
- * the VNIC MAC forwarding table. It checks for the validity of
- * the index into the MAC table and the number of entries that
- * are to be retrieved.
- */
- static void vema_get_mac_entries(struct opa_vnic_vema_port *port,
- struct opa_vnic_vema_mad *recvd_mad,
- struct opa_vnic_vema_mad *rsp_mad)
- {
- struct opa_veswport_mactable *mac_tbl_in, *mac_tbl_out;
- struct opa_vnic_adapter *adapter;
- adapter = vema_get_vport_adapter(recvd_mad, port);
- if (!adapter) {
- rsp_mad->mad_hdr.status = OPA_VNIC_INVAL_ATTR;
- return;
- }
- mac_tbl_in = (struct opa_veswport_mactable *)recvd_mad->data;
- mac_tbl_out = (struct opa_veswport_mactable *)rsp_mad->data;
- if (vema_mac_tbl_req_ok(mac_tbl_in)) {
- mac_tbl_out->offset = mac_tbl_in->offset;
- mac_tbl_out->num_entries = mac_tbl_in->num_entries;
- opa_vnic_query_mac_tbl(adapter, mac_tbl_out);
- } else {
- rsp_mad->mad_hdr.status = OPA_VNIC_INVAL_ATTR;
- }
- }
- /**
- * vema_set_mac_entries -- Set MAC entries in VNIC MAC table
- * @port: source port on which MAD was received
- * @recvd_mad: pointer to the received mad
- * @rsp_mad: pointer to respose mad
- *
- * This function sets the MAC entries in the VNIC forwarding table
- * It checks for the validity of the index and the number of forwarding
- * table entries to be programmed.
- */
- static void vema_set_mac_entries(struct opa_vnic_vema_port *port,
- struct opa_vnic_vema_mad *recvd_mad,
- struct opa_vnic_vema_mad *rsp_mad)
- {
- struct opa_veswport_mactable *mac_tbl;
- struct opa_vnic_adapter *adapter;
- adapter = vema_get_vport_adapter(recvd_mad, port);
- if (!adapter) {
- rsp_mad->mad_hdr.status = OPA_VNIC_INVAL_ATTR;
- return;
- }
- mac_tbl = (struct opa_veswport_mactable *)recvd_mad->data;
- if (vema_mac_tbl_req_ok(mac_tbl)) {
- if (opa_vnic_update_mac_tbl(adapter, mac_tbl))
- rsp_mad->mad_hdr.status = OPA_VNIC_UNSUP_ATTR;
- } else {
- rsp_mad->mad_hdr.status = OPA_VNIC_UNSUP_ATTR;
- }
- vema_get_mac_entries(port, recvd_mad, rsp_mad);
- }
- /**
- * vema_set_delete_vesw -- Reset VESW info to POD values
- * @port: source port on which MAD was received
- * @recvd_mad: pointer to the received mad
- * @rsp_mad: pointer to respose mad
- *
- * This function clears all the fields of veswport info for the requested vesw
- * and sets them back to the power-on default values. It does not delete the
- * vesw.
- */
- static void vema_set_delete_vesw(struct opa_vnic_vema_port *port,
- struct opa_vnic_vema_mad *recvd_mad,
- struct opa_vnic_vema_mad *rsp_mad)
- {
- struct opa_veswport_info *port_info =
- (struct opa_veswport_info *)rsp_mad->data;
- struct opa_vnic_adapter *adapter;
- adapter = vema_get_vport_adapter(recvd_mad, port);
- if (!adapter) {
- rsp_mad->mad_hdr.status = OPA_VNIC_INVAL_ATTR;
- return;
- }
- vema_get_pod_values(port_info);
- opa_vnic_set_vesw_info(adapter, &port_info->vesw);
- opa_vnic_set_per_veswport_info(adapter, &port_info->vport);
- /* Process the new config settings */
- opa_vnic_process_vema_config(adapter);
- opa_vnic_release_mac_tbl(adapter);
- vema_get_veswport_info(port, recvd_mad, rsp_mad);
- }
- /**
- * vema_get_mac_list -- Get the unicast/multicast macs.
- * @port: source port on which MAD was received
- * @recvd_mad: Received mad contains fields to set vnic parameters
- * @rsp_mad: Response mad to be built
- * @attr_id: Attribute ID indicating multicast or unicast mac list
- */
- static void 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)
- {
- struct opa_veswport_iface_macs *macs_in, *macs_out;
- int max_entries = (OPA_VNIC_EMA_DATA - sizeof(*macs_out)) / ETH_ALEN;
- struct opa_vnic_adapter *adapter;
- adapter = vema_get_vport_adapter(recvd_mad, port);
- if (!adapter) {
- rsp_mad->mad_hdr.status = OPA_VNIC_INVAL_ATTR;
- return;
- }
- macs_in = (struct opa_veswport_iface_macs *)recvd_mad->data;
- macs_out = (struct opa_veswport_iface_macs *)rsp_mad->data;
- macs_out->start_idx = macs_in->start_idx;
- if (macs_in->num_macs_in_msg)
- macs_out->num_macs_in_msg = macs_in->num_macs_in_msg;
- else
- macs_out->num_macs_in_msg = cpu_to_be16(max_entries);
- if (attr_id == OPA_EM_ATTR_IFACE_MCAST_MACS)
- opa_vnic_query_mcast_macs(adapter, macs_out);
- else
- opa_vnic_query_ucast_macs(adapter, macs_out);
- }
- /**
- * vema_get_summary_counters -- Gets summary counters.
- * @port: source port on which MAD was received
- * @recvd_mad: Received mad contains fields to set vnic parameters
- * @rsp_mad: Response mad to be built
- */
- static void vema_get_summary_counters(struct opa_vnic_vema_port *port,
- struct opa_vnic_vema_mad *recvd_mad,
- struct opa_vnic_vema_mad *rsp_mad)
- {
- struct opa_veswport_summary_counters *cntrs;
- struct opa_vnic_adapter *adapter;
- adapter = vema_get_vport_adapter(recvd_mad, port);
- if (adapter) {
- cntrs = (struct opa_veswport_summary_counters *)rsp_mad->data;
- opa_vnic_get_summary_counters(adapter, cntrs);
- } else {
- rsp_mad->mad_hdr.status = OPA_VNIC_INVAL_ATTR;
- }
- }
- /**
- * vema_get_error_counters -- Gets summary counters.
- * @port: source port on which MAD was received
- * @recvd_mad: Received mad contains fields to set vnic parameters
- * @rsp_mad: Response mad to be built
- */
- static void vema_get_error_counters(struct opa_vnic_vema_port *port,
- struct opa_vnic_vema_mad *recvd_mad,
- struct opa_vnic_vema_mad *rsp_mad)
- {
- struct opa_veswport_error_counters *cntrs;
- struct opa_vnic_adapter *adapter;
- adapter = vema_get_vport_adapter(recvd_mad, port);
- if (adapter) {
- cntrs = (struct opa_veswport_error_counters *)rsp_mad->data;
- opa_vnic_get_error_counters(adapter, cntrs);
- } else {
- rsp_mad->mad_hdr.status = OPA_VNIC_INVAL_ATTR;
- }
- }
- /**
- * vema_get -- Process received get MAD
- * @port: source port on which MAD was received
- * @recvd_mad: Received mad
- * @rsp_mad: Response mad to be built
- */
- static void vema_get(struct opa_vnic_vema_port *port,
- struct opa_vnic_vema_mad *recvd_mad,
- struct opa_vnic_vema_mad *rsp_mad)
- {
- u16 attr_id = be16_to_cpu(recvd_mad->mad_hdr.attr_id);
- switch (attr_id) {
- case OPA_EM_ATTR_CLASS_PORT_INFO:
- vema_get_class_port_info(port, recvd_mad, rsp_mad);
- break;
- case OPA_EM_ATTR_VESWPORT_INFO:
- vema_get_veswport_info(port, recvd_mad, rsp_mad);
- break;
- case OPA_EM_ATTR_VESWPORT_MAC_ENTRIES:
- vema_get_mac_entries(port, recvd_mad, rsp_mad);
- break;
- case OPA_EM_ATTR_IFACE_UCAST_MACS:
- /* fall through */
- case OPA_EM_ATTR_IFACE_MCAST_MACS:
- vema_get_mac_list(port, recvd_mad, rsp_mad, attr_id);
- break;
- case OPA_EM_ATTR_VESWPORT_SUMMARY_COUNTERS:
- vema_get_summary_counters(port, recvd_mad, rsp_mad);
- break;
- case OPA_EM_ATTR_VESWPORT_ERROR_COUNTERS:
- vema_get_error_counters(port, recvd_mad, rsp_mad);
- break;
- default:
- rsp_mad->mad_hdr.status = OPA_VNIC_UNSUP_ATTR;
- break;
- }
- }
- /**
- * vema_set -- Process received set MAD
- * @port: source port on which MAD was received
- * @recvd_mad: Received mad contains fields to set vnic parameters
- * @rsp_mad: Response mad to be built
- */
- static void vema_set(struct opa_vnic_vema_port *port,
- struct opa_vnic_vema_mad *recvd_mad,
- struct opa_vnic_vema_mad *rsp_mad)
- {
- u16 attr_id = be16_to_cpu(recvd_mad->mad_hdr.attr_id);
- switch (attr_id) {
- case OPA_EM_ATTR_CLASS_PORT_INFO:
- vema_set_class_port_info(port, recvd_mad, rsp_mad);
- break;
- case OPA_EM_ATTR_VESWPORT_INFO:
- vema_set_veswport_info(port, recvd_mad, rsp_mad);
- break;
- case OPA_EM_ATTR_VESWPORT_MAC_ENTRIES:
- vema_set_mac_entries(port, recvd_mad, rsp_mad);
- break;
- case OPA_EM_ATTR_DELETE_VESW:
- vema_set_delete_vesw(port, recvd_mad, rsp_mad);
- break;
- default:
- rsp_mad->mad_hdr.status = OPA_VNIC_UNSUP_ATTR;
- break;
- }
- }
- /**
- * vema_send -- Send handler for VEMA MAD agent
- * @mad_agent: pointer to the mad agent
- * @mad_wc: pointer to mad send work completion information
- *
- * Free all the data structures associated with the sent MAD
- */
- static void vema_send(struct ib_mad_agent *mad_agent,
- struct ib_mad_send_wc *mad_wc)
- {
- rdma_destroy_ah(mad_wc->send_buf->ah);
- ib_free_send_mad(mad_wc->send_buf);
- }
- /**
- * vema_recv -- Recv handler for VEMA MAD agent
- * @mad_agent: pointer to the mad agent
- * @send_buf: Send buffer if found, else NULL
- * @mad_wc: pointer to mad send work completion information
- *
- * Handle only set and get methods and respond to other methods
- * as unsupported. Allocate response buffer and address handle
- * for the response MAD.
- */
- static void vema_recv(struct ib_mad_agent *mad_agent,
- struct ib_mad_send_buf *send_buf,
- struct ib_mad_recv_wc *mad_wc)
- {
- struct opa_vnic_vema_port *port;
- struct ib_ah *ah;
- struct ib_mad_send_buf *rsp;
- struct opa_vnic_vema_mad *vema_mad;
- if (!mad_wc || !mad_wc->recv_buf.mad)
- return;
- port = mad_agent->context;
- ah = ib_create_ah_from_wc(mad_agent->qp->pd, mad_wc->wc,
- mad_wc->recv_buf.grh, mad_agent->port_num);
- if (IS_ERR(ah))
- goto free_recv_mad;
- rsp = ib_create_send_mad(mad_agent, mad_wc->wc->src_qp,
- mad_wc->wc->pkey_index, 0,
- IB_MGMT_VENDOR_HDR, OPA_VNIC_EMA_DATA,
- GFP_KERNEL, OPA_MGMT_BASE_VERSION);
- if (IS_ERR(rsp))
- goto err_rsp;
- rsp->ah = ah;
- vema_mad = rsp->mad;
- memcpy(vema_mad, mad_wc->recv_buf.mad, IB_MGMT_VENDOR_HDR);
- vema_mad->mad_hdr.method = IB_MGMT_METHOD_GET_RESP;
- vema_mad->mad_hdr.status = 0;
- /* Lock ensures network adapter is not removed */
- mutex_lock(&port->lock);
- switch (mad_wc->recv_buf.mad->mad_hdr.method) {
- case IB_MGMT_METHOD_GET:
- vema_get(port, (struct opa_vnic_vema_mad *)mad_wc->recv_buf.mad,
- vema_mad);
- break;
- case IB_MGMT_METHOD_SET:
- vema_set(port, (struct opa_vnic_vema_mad *)mad_wc->recv_buf.mad,
- vema_mad);
- break;
- default:
- vema_mad->mad_hdr.status = OPA_VNIC_UNSUP_ATTR;
- break;
- }
- mutex_unlock(&port->lock);
- if (!ib_post_send_mad(rsp, NULL)) {
- /*
- * with post send successful ah and send mad
- * will be destroyed in send handler
- */
- goto free_recv_mad;
- }
- ib_free_send_mad(rsp);
- err_rsp:
- rdma_destroy_ah(ah);
- free_recv_mad:
- ib_free_recv_mad(mad_wc);
- }
- /**
- * vema_get_port -- Gets the opa_vnic_vema_port
- * @cport: pointer to control dev
- * @port_num: Port number
- *
- * This function loops through the ports and returns
- * the opa_vnic_vema port structure that is associated
- * with the OPA port number
- *
- * Return: ptr to requested opa_vnic_vema_port strucure
- * if success, NULL if not
- */
- static struct opa_vnic_vema_port *
- vema_get_port(struct opa_vnic_ctrl_port *cport, u8 port_num)
- {
- struct opa_vnic_vema_port *port = (void *)cport + sizeof(*cport);
- if (port_num > cport->num_ports)
- return NULL;
- return port + (port_num - 1);
- }
- /**
- * opa_vnic_vema_send_trap -- This function sends a trap to the EM
- * @adapter: pointer to vnic adapter
- * @data: pointer to trap data filled by calling function
- * @lid: issuers lid (encap_slid from vesw_port_info)
- *
- * This function is called from the VNIC driver to send a trap if there
- * is somethng the EM should be notified about. These events currently
- * are
- * 1) UNICAST INTERFACE MACADDRESS changes
- * 2) MULTICAST INTERFACE MACADDRESS changes
- * 3) ETHERNET LINK STATUS changes
- * While allocating the send mad the remote site qpn used is 1
- * as this is the well known QP.
- *
- */
- void opa_vnic_vema_send_trap(struct opa_vnic_adapter *adapter,
- struct __opa_veswport_trap *data, u32 lid)
- {
- struct opa_vnic_ctrl_port *cport = adapter->cport;
- struct ib_mad_send_buf *send_buf;
- struct opa_vnic_vema_port *port;
- struct ib_device *ibp;
- struct opa_vnic_vema_mad_trap *trap_mad;
- struct opa_class_port_info *class;
- struct rdma_ah_attr ah_attr;
- struct ib_ah *ah;
- struct opa_veswport_trap *trap;
- u32 trap_lid;
- u16 pkey_idx;
- if (!cport)
- goto err_exit;
- ibp = cport->ibdev;
- port = vema_get_port(cport, data->opaportnum);
- if (!port || !port->mad_agent)
- goto err_exit;
- if (time_before(jiffies, adapter->trap_timeout)) {
- if (adapter->trap_count == OPA_VNIC_TRAP_BURST_LIMIT) {
- v_warn("Trap rate exceeded\n");
- goto err_exit;
- } else {
- adapter->trap_count++;
- }
- } else {
- adapter->trap_count = 0;
- }
- class = &port->class_port_info;
- /* Set up address handle */
- memset(&ah_attr, 0, sizeof(ah_attr));
- ah_attr.type = rdma_ah_find_type(ibp, port->port_num);
- rdma_ah_set_sl(&ah_attr,
- GET_TRAP_SL_FROM_CLASS_PORT_INFO(class->trap_sl_rsvd));
- rdma_ah_set_port_num(&ah_attr, port->port_num);
- trap_lid = be32_to_cpu(class->trap_lid);
- /*
- * check for trap lid validity, must not be zero
- * The trap sink could change after we fashion the MAD but since traps
- * are not guaranteed we won't use a lock as anyway the change will take
- * place even with locking.
- */
- if (!trap_lid) {
- c_err("%s: Invalid dlid\n", __func__);
- goto err_exit;
- }
- rdma_ah_set_dlid(&ah_attr, trap_lid);
- ah = rdma_create_ah(port->mad_agent->qp->pd, &ah_attr);
- if (IS_ERR(ah)) {
- c_err("%s:Couldn't create new AH = %p\n", __func__, ah);
- c_err("%s:dlid = %d, sl = %d, port = %d\n", __func__,
- rdma_ah_get_dlid(&ah_attr), rdma_ah_get_sl(&ah_attr),
- rdma_ah_get_port_num(&ah_attr));
- goto err_exit;
- }
- if (ib_find_pkey(ibp, data->opaportnum, IB_DEFAULT_PKEY_FULL,
- &pkey_idx) < 0) {
- c_err("%s:full key not found, defaulting to partial\n",
- __func__);
- if (ib_find_pkey(ibp, data->opaportnum, IB_DEFAULT_PKEY_PARTIAL,
- &pkey_idx) < 0)
- pkey_idx = 1;
- }
- send_buf = ib_create_send_mad(port->mad_agent, 1, pkey_idx, 0,
- IB_MGMT_VENDOR_HDR, IB_MGMT_MAD_DATA,
- GFP_ATOMIC, OPA_MGMT_BASE_VERSION);
- if (IS_ERR(send_buf)) {
- c_err("%s:Couldn't allocate send buf\n", __func__);
- goto err_sndbuf;
- }
- send_buf->ah = ah;
- /* Set up common MAD hdr */
- trap_mad = send_buf->mad;
- trap_mad->mad_hdr.base_version = OPA_MGMT_BASE_VERSION;
- trap_mad->mad_hdr.mgmt_class = OPA_MGMT_CLASS_INTEL_EMA;
- trap_mad->mad_hdr.class_version = OPA_EMA_CLASS_VERSION;
- trap_mad->mad_hdr.method = IB_MGMT_METHOD_TRAP;
- port->tid++;
- trap_mad->mad_hdr.tid = cpu_to_be64(port->tid);
- trap_mad->mad_hdr.attr_id = IB_SMP_ATTR_NOTICE;
- /* Set up vendor OUI */
- trap_mad->oui[0] = INTEL_OUI_1;
- trap_mad->oui[1] = INTEL_OUI_2;
- trap_mad->oui[2] = INTEL_OUI_3;
- /* Setup notice attribute portion */
- trap_mad->notice.gen_type = OPA_INTEL_EMA_NOTICE_TYPE_INFO << 1;
- trap_mad->notice.oui_1 = INTEL_OUI_1;
- trap_mad->notice.oui_2 = INTEL_OUI_2;
- trap_mad->notice.oui_3 = INTEL_OUI_3;
- trap_mad->notice.issuer_lid = cpu_to_be32(lid);
- /* copy the actual trap data */
- trap = (struct opa_veswport_trap *)trap_mad->notice.raw_data;
- trap->fabric_id = cpu_to_be16(data->fabric_id);
- trap->veswid = cpu_to_be16(data->veswid);
- trap->veswportnum = cpu_to_be32(data->veswportnum);
- trap->opaportnum = cpu_to_be16(data->opaportnum);
- trap->veswportindex = data->veswportindex;
- trap->opcode = data->opcode;
- /* If successful send set up rate limit timeout else bail */
- if (ib_post_send_mad(send_buf, NULL)) {
- ib_free_send_mad(send_buf);
- } else {
- if (adapter->trap_count)
- return;
- adapter->trap_timeout = jiffies +
- usecs_to_jiffies(OPA_VNIC_TRAP_TIMEOUT);
- return;
- }
- err_sndbuf:
- rdma_destroy_ah(ah);
- err_exit:
- v_err("Aborting trap\n");
- }
- static int vema_rem_vport(int id, void *p, void *data)
- {
- struct opa_vnic_adapter *adapter = p;
- opa_vnic_rem_netdev(adapter);
- return 0;
- }
- static int vema_enable_vport(int id, void *p, void *data)
- {
- struct opa_vnic_adapter *adapter = p;
- netif_carrier_on(adapter->netdev);
- return 0;
- }
- static int vema_disable_vport(int id, void *p, void *data)
- {
- struct opa_vnic_adapter *adapter = p;
- netif_carrier_off(adapter->netdev);
- return 0;
- }
- static void opa_vnic_event(struct ib_event_handler *handler,
- struct ib_event *record)
- {
- struct opa_vnic_vema_port *port =
- container_of(handler, struct opa_vnic_vema_port, event_handler);
- struct opa_vnic_ctrl_port *cport = port->cport;
- if (record->element.port_num != port->port_num)
- return;
- c_dbg("OPA_VNIC received event %d on device %s port %d\n",
- record->event, record->device->name, record->element.port_num);
- if (record->event == IB_EVENT_PORT_ERR)
- idr_for_each(&port->vport_idr, vema_disable_vport, NULL);
- if (record->event == IB_EVENT_PORT_ACTIVE)
- idr_for_each(&port->vport_idr, vema_enable_vport, NULL);
- }
- /**
- * vema_unregister -- Unregisters agent
- * @cport: pointer to control port
- *
- * This deletes the registration by VEMA for MADs
- */
- static void vema_unregister(struct opa_vnic_ctrl_port *cport)
- {
- int i;
- for (i = 1; i <= cport->num_ports; i++) {
- struct opa_vnic_vema_port *port = vema_get_port(cport, i);
- if (!port->mad_agent)
- continue;
- /* Lock ensures no MAD is being processed */
- mutex_lock(&port->lock);
- idr_for_each(&port->vport_idr, vema_rem_vport, NULL);
- mutex_unlock(&port->lock);
- ib_unregister_mad_agent(port->mad_agent);
- port->mad_agent = NULL;
- mutex_destroy(&port->lock);
- idr_destroy(&port->vport_idr);
- ib_unregister_event_handler(&port->event_handler);
- }
- }
- /**
- * vema_register -- Registers agent
- * @cport: pointer to control port
- *
- * This function registers the handlers for the VEMA MADs
- *
- * Return: returns 0 on success. non zero otherwise
- */
- static int vema_register(struct opa_vnic_ctrl_port *cport)
- {
- struct ib_mad_reg_req reg_req = {
- .mgmt_class = OPA_MGMT_CLASS_INTEL_EMA,
- .mgmt_class_version = OPA_MGMT_BASE_VERSION,
- .oui = { INTEL_OUI_1, INTEL_OUI_2, INTEL_OUI_3 }
- };
- int i;
- set_bit(IB_MGMT_METHOD_GET, reg_req.method_mask);
- set_bit(IB_MGMT_METHOD_SET, reg_req.method_mask);
- /* register ib event handler and mad agent for each port on dev */
- for (i = 1; i <= cport->num_ports; i++) {
- struct opa_vnic_vema_port *port = vema_get_port(cport, i);
- int ret;
- port->cport = cport;
- port->port_num = i;
- INIT_IB_EVENT_HANDLER(&port->event_handler,
- cport->ibdev, opa_vnic_event);
- ib_register_event_handler(&port->event_handler);
- idr_init(&port->vport_idr);
- mutex_init(&port->lock);
- port->mad_agent = ib_register_mad_agent(cport->ibdev, i,
- IB_QPT_GSI, ®_req,
- IB_MGMT_RMPP_VERSION,
- vema_send, vema_recv,
- port, 0);
- if (IS_ERR(port->mad_agent)) {
- ret = PTR_ERR(port->mad_agent);
- port->mad_agent = NULL;
- mutex_destroy(&port->lock);
- idr_destroy(&port->vport_idr);
- vema_unregister(cport);
- return ret;
- }
- }
- return 0;
- }
- /**
- * opa_vnic_ctrl_config_dev -- This function sends a trap to the EM
- * by way of ib_modify_port to indicate support for ethernet on the
- * fabric.
- * @cport: pointer to control port
- * @en: enable or disable ethernet on fabric support
- */
- static void opa_vnic_ctrl_config_dev(struct opa_vnic_ctrl_port *cport, bool en)
- {
- struct ib_port_modify pm = { 0 };
- int i;
- if (en)
- pm.set_port_cap_mask = OPA_CAP_MASK3_IsEthOnFabricSupported;
- else
- pm.clr_port_cap_mask = OPA_CAP_MASK3_IsEthOnFabricSupported;
- for (i = 1; i <= cport->num_ports; i++)
- ib_modify_port(cport->ibdev, i, IB_PORT_OPA_MASK_CHG, &pm);
- }
- /**
- * opa_vnic_vema_add_one -- Handle new ib device
- * @device: ib device pointer
- *
- * Allocate the vnic control port and initialize it.
- */
- static void opa_vnic_vema_add_one(struct ib_device *device)
- {
- struct opa_vnic_ctrl_port *cport;
- int rc, size = sizeof(*cport);
- if (!rdma_cap_opa_vnic(device))
- return;
- size += device->phys_port_cnt * sizeof(struct opa_vnic_vema_port);
- cport = kzalloc(size, GFP_KERNEL);
- if (!cport)
- return;
- cport->num_ports = device->phys_port_cnt;
- cport->ibdev = device;
- /* Initialize opa vnic management agent (vema) */
- rc = vema_register(cport);
- if (!rc)
- c_info("VNIC client initialized\n");
- ib_set_client_data(device, &opa_vnic_client, cport);
- opa_vnic_ctrl_config_dev(cport, true);
- }
- /**
- * opa_vnic_vema_rem_one -- Handle ib device removal
- * @device: ib device pointer
- * @client_data: ib client data
- *
- * Uninitialize and free the vnic control port.
- */
- static void opa_vnic_vema_rem_one(struct ib_device *device,
- void *client_data)
- {
- struct opa_vnic_ctrl_port *cport = client_data;
- if (!cport)
- return;
- c_info("removing VNIC client\n");
- opa_vnic_ctrl_config_dev(cport, false);
- vema_unregister(cport);
- kfree(cport);
- }
- static int __init opa_vnic_init(void)
- {
- int rc;
- pr_info("OPA Virtual Network Driver - v%s\n",
- opa_vnic_driver_version);
- rc = ib_register_client(&opa_vnic_client);
- if (rc)
- pr_err("VNIC driver register failed %d\n", rc);
- return rc;
- }
- module_init(opa_vnic_init);
- static void opa_vnic_deinit(void)
- {
- ib_unregister_client(&opa_vnic_client);
- }
- module_exit(opa_vnic_deinit);
- MODULE_LICENSE("Dual BSD/GPL");
- MODULE_AUTHOR("Intel Corporation");
- MODULE_DESCRIPTION("Intel OPA Virtual Network driver");
|