Resguardo inicial

This commit is contained in:
lastdragon
2026-09-06 12:53:21 -06:00
parent 662efe3c2a
commit ad2088d178
94853 changed files with 43200404 additions and 0 deletions
+25
View File
@@ -0,0 +1,25 @@
# SPDX-License-Identifier: GPL-2.0-only
#
# Configuration for NCSI support
#
config NET_NCSI
bool "NCSI interface support"
depends on INET
help
This module provides NCSI (Network Controller Sideband Interface)
support. Enable this only if your system connects to a network
device via NCSI and the ethernet driver you're using supports
the protocol explicitly.
config NCSI_OEM_CMD_GET_MAC
bool "Get NCSI OEM MAC Address"
depends on NET_NCSI
help
This allows to get MAC address from NCSI firmware and set them back to
controller.
config NCSI_OEM_CMD_KEEP_PHY
bool "Keep PHY Link up"
depends on NET_NCSI
help
This allows to keep PHY link up and prevents any channel resets during
the host load.
+5
View File
@@ -0,0 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-only
#
# Makefile for NCSI API
#
obj-$(CONFIG_NET_NCSI) += ncsi-cmd.o ncsi-rsp.o ncsi-aen.o ncsi-manage.o ncsi-netlink.o
+417
View File
@@ -0,0 +1,417 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* Copyright Gavin Shan, IBM Corporation 2016.
*/
#ifndef __NCSI_INTERNAL_H__
#define __NCSI_INTERNAL_H__
enum {
NCSI_CAP_BASE = 0,
NCSI_CAP_GENERIC = 0,
NCSI_CAP_BC,
NCSI_CAP_MC,
NCSI_CAP_BUFFER,
NCSI_CAP_AEN,
NCSI_CAP_VLAN,
NCSI_CAP_MAX
};
enum {
NCSI_CAP_GENERIC_HWA = 0x01, /* HW arbitration */
NCSI_CAP_GENERIC_HDS = 0x02, /* HNC driver status change */
NCSI_CAP_GENERIC_FC = 0x04, /* HNC to MC flow control */
NCSI_CAP_GENERIC_FC1 = 0x08, /* MC to HNC flow control */
NCSI_CAP_GENERIC_MC = 0x10, /* Global MC filtering */
NCSI_CAP_GENERIC_HWA_UNKNOWN = 0x00, /* Unknown HW arbitration */
NCSI_CAP_GENERIC_HWA_SUPPORT = 0x20, /* Supported HW arbitration */
NCSI_CAP_GENERIC_HWA_NOT_SUPPORT = 0x40, /* No HW arbitration */
NCSI_CAP_GENERIC_HWA_RESERVED = 0x60, /* Reserved HW arbitration */
NCSI_CAP_GENERIC_HWA_MASK = 0x60, /* Mask for HW arbitration */
NCSI_CAP_GENERIC_MASK = 0x7f,
NCSI_CAP_BC_ARP = 0x01, /* ARP packet filtering */
NCSI_CAP_BC_DHCPC = 0x02, /* DHCP client filtering */
NCSI_CAP_BC_DHCPS = 0x04, /* DHCP server filtering */
NCSI_CAP_BC_NETBIOS = 0x08, /* NetBIOS packet filtering */
NCSI_CAP_BC_MASK = 0x0f,
NCSI_CAP_MC_IPV6_NEIGHBOR = 0x01, /* IPv6 neighbor filtering */
NCSI_CAP_MC_IPV6_ROUTER = 0x02, /* IPv6 router filering */
NCSI_CAP_MC_DHCPV6_RELAY = 0x04, /* DHCPv6 relay / server MC */
NCSI_CAP_MC_DHCPV6_WELL_KNOWN = 0x08, /* DHCPv6 well-known MC */
NCSI_CAP_MC_IPV6_MLD = 0x10, /* IPv6 MLD filtering */
NCSI_CAP_MC_IPV6_NEIGHBOR_S = 0x20, /* IPv6 neighbour filtering */
NCSI_CAP_MC_MASK = 0x3f,
NCSI_CAP_AEN_LSC = 0x01, /* Link status change */
NCSI_CAP_AEN_CR = 0x02, /* Configuration required */
NCSI_CAP_AEN_HDS = 0x04, /* HNC driver status */
NCSI_CAP_AEN_MASK = 0x07,
NCSI_CAP_VLAN_ONLY = 0x01, /* Filter VLAN packet only */
NCSI_CAP_VLAN_NO = 0x02, /* Filter VLAN and non-VLAN */
NCSI_CAP_VLAN_ANY = 0x04, /* Filter Any-and-non-VLAN */
NCSI_CAP_VLAN_MASK = 0x07
};
enum {
NCSI_MODE_BASE = 0,
NCSI_MODE_ENABLE = 0,
NCSI_MODE_TX_ENABLE,
NCSI_MODE_LINK,
NCSI_MODE_VLAN,
NCSI_MODE_BC,
NCSI_MODE_MC,
NCSI_MODE_AEN,
NCSI_MODE_FC,
NCSI_MODE_MAX
};
/* Supported media status bits for Mellanox Mac affinity command.
* Bit (0-2) for different protocol support; Bit 1 for RBT support,
* bit 1 for SMBUS support and bit 2 for PCIE support. Bit (3-5)
* for different protocol availability. Bit 4 for RBT, bit 4 for
* SMBUS and bit 5 for PCIE.
*/
enum {
MLX_MC_RBT_SUPPORT = 0x01, /* MC supports RBT */
MLX_MC_RBT_AVL = 0x08, /* RBT medium is available */
};
/* OEM Vendor Manufacture ID */
#define NCSI_OEM_MFR_MLX_ID 0x8119
#define NCSI_OEM_MFR_BCM_ID 0x113d
#define NCSI_OEM_MFR_INTEL_ID 0x157
/* Intel specific OEM command */
#define NCSI_OEM_INTEL_CMD_GMA 0x06 /* CMD ID for Get MAC */
#define NCSI_OEM_INTEL_CMD_KEEP_PHY 0x20 /* CMD ID for Keep PHY up */
/* Broadcom specific OEM Command */
#define NCSI_OEM_BCM_CMD_GMA 0x01 /* CMD ID for Get MAC */
/* Mellanox specific OEM Command */
#define NCSI_OEM_MLX_CMD_GMA 0x00 /* CMD ID for Get MAC */
#define NCSI_OEM_MLX_CMD_GMA_PARAM 0x1b /* Parameter for GMA */
#define NCSI_OEM_MLX_CMD_SMAF 0x01 /* CMD ID for Set MC Affinity */
#define NCSI_OEM_MLX_CMD_SMAF_PARAM 0x07 /* Parameter for SMAF */
/* OEM Command payload lengths*/
#define NCSI_OEM_INTEL_CMD_GMA_LEN 5
#define NCSI_OEM_INTEL_CMD_KEEP_PHY_LEN 7
#define NCSI_OEM_BCM_CMD_GMA_LEN 12
#define NCSI_OEM_MLX_CMD_GMA_LEN 8
#define NCSI_OEM_MLX_CMD_SMAF_LEN 60
/* Offset in OEM request */
#define MLX_SMAF_MAC_ADDR_OFFSET 8 /* Offset for MAC in SMAF */
#define MLX_SMAF_MED_SUPPORT_OFFSET 14 /* Offset for medium in SMAF */
/* Mac address offset in OEM response */
#define BCM_MAC_ADDR_OFFSET 28
#define MLX_MAC_ADDR_OFFSET 8
#define INTEL_MAC_ADDR_OFFSET 1
struct ncsi_channel_version {
u8 major; /* NCSI version major */
u8 minor; /* NCSI version minor */
u8 update; /* NCSI version update */
char alpha1; /* NCSI version alpha1 */
char alpha2; /* NCSI version alpha2 */
u8 fw_name[12 + 1]; /* Firmware name string */
u32 fw_version; /* Firmware version */
u16 pci_ids[4]; /* PCI identification */
u32 mf_id; /* Manufacture ID */
};
struct ncsi_channel_cap {
u32 index; /* Index of channel capabilities */
u32 cap; /* NCSI channel capability */
};
struct ncsi_channel_mode {
u32 index; /* Index of channel modes */
u32 enable; /* Enabled or disabled */
u32 size; /* Valid entries in ncm_data[] */
u32 data[8]; /* Data entries */
};
struct ncsi_channel_mac_filter {
u8 n_uc;
u8 n_mc;
u8 n_mixed;
u64 bitmap;
unsigned char *addrs;
};
struct ncsi_channel_vlan_filter {
u8 n_vids;
u64 bitmap;
u16 *vids;
};
struct ncsi_channel_stats {
u64 hnc_cnt; /* Counter cleared */
u64 hnc_rx_bytes; /* Rx bytes */
u64 hnc_tx_bytes; /* Tx bytes */
u64 hnc_rx_uc_pkts; /* Rx UC packets */
u64 hnc_rx_mc_pkts; /* Rx MC packets */
u64 hnc_rx_bc_pkts; /* Rx BC packets */
u64 hnc_tx_uc_pkts; /* Tx UC packets */
u64 hnc_tx_mc_pkts; /* Tx MC packets */
u64 hnc_tx_bc_pkts; /* Tx BC packets */
u32 hnc_fcs_err; /* FCS errors */
u32 hnc_align_err; /* Alignment errors */
u32 hnc_false_carrier; /* False carrier detection */
u32 hnc_runt_pkts; /* Rx runt packets */
u32 hnc_jabber_pkts; /* Rx jabber packets */
u32 hnc_rx_pause_xon; /* Rx pause XON frames */
u32 hnc_rx_pause_xoff; /* Rx XOFF frames */
u32 hnc_tx_pause_xon; /* Tx XON frames */
u32 hnc_tx_pause_xoff; /* Tx XOFF frames */
u32 hnc_tx_s_collision; /* Single collision frames */
u32 hnc_tx_m_collision; /* Multiple collision frames */
u32 hnc_l_collision; /* Late collision frames */
u32 hnc_e_collision; /* Excessive collision frames */
u32 hnc_rx_ctl_frames; /* Rx control frames */
u32 hnc_rx_64_frames; /* Rx 64-bytes frames */
u32 hnc_rx_127_frames; /* Rx 65-127 bytes frames */
u32 hnc_rx_255_frames; /* Rx 128-255 bytes frames */
u32 hnc_rx_511_frames; /* Rx 256-511 bytes frames */
u32 hnc_rx_1023_frames; /* Rx 512-1023 bytes frames */
u32 hnc_rx_1522_frames; /* Rx 1024-1522 bytes frames */
u32 hnc_rx_9022_frames; /* Rx 1523-9022 bytes frames */
u32 hnc_tx_64_frames; /* Tx 64-bytes frames */
u32 hnc_tx_127_frames; /* Tx 65-127 bytes frames */
u32 hnc_tx_255_frames; /* Tx 128-255 bytes frames */
u32 hnc_tx_511_frames; /* Tx 256-511 bytes frames */
u32 hnc_tx_1023_frames; /* Tx 512-1023 bytes frames */
u32 hnc_tx_1522_frames; /* Tx 1024-1522 bytes frames */
u32 hnc_tx_9022_frames; /* Tx 1523-9022 bytes frames */
u64 hnc_rx_valid_bytes; /* Rx valid bytes */
u32 hnc_rx_runt_pkts; /* Rx error runt packets */
u32 hnc_rx_jabber_pkts; /* Rx error jabber packets */
u32 ncsi_rx_cmds; /* Rx NCSI commands */
u32 ncsi_dropped_cmds; /* Dropped commands */
u32 ncsi_cmd_type_errs; /* Command type errors */
u32 ncsi_cmd_csum_errs; /* Command checksum errors */
u32 ncsi_rx_pkts; /* Rx NCSI packets */
u32 ncsi_tx_pkts; /* Tx NCSI packets */
u32 ncsi_tx_aen_pkts; /* Tx AEN packets */
u32 pt_tx_pkts; /* Tx packets */
u32 pt_tx_dropped; /* Tx dropped packets */
u32 pt_tx_channel_err; /* Tx channel errors */
u32 pt_tx_us_err; /* Tx undersize errors */
u32 pt_rx_pkts; /* Rx packets */
u32 pt_rx_dropped; /* Rx dropped packets */
u32 pt_rx_channel_err; /* Rx channel errors */
u32 pt_rx_us_err; /* Rx undersize errors */
u32 pt_rx_os_err; /* Rx oversize errors */
};
struct ncsi_dev_priv;
struct ncsi_package;
#define NCSI_PACKAGE_SHIFT 5
#define NCSI_PACKAGE_INDEX(c) (((c) >> NCSI_PACKAGE_SHIFT) & 0x7)
#define NCSI_RESERVED_CHANNEL 0x1f
#define NCSI_CHANNEL_INDEX(c) ((c) & ((1 << NCSI_PACKAGE_SHIFT) - 1))
#define NCSI_TO_CHANNEL(p, c) (((p) << NCSI_PACKAGE_SHIFT) | (c))
#define NCSI_MAX_PACKAGE 8
#define NCSI_MAX_CHANNEL 32
struct ncsi_channel {
unsigned char id;
int state;
#define NCSI_CHANNEL_INACTIVE 1
#define NCSI_CHANNEL_ACTIVE 2
#define NCSI_CHANNEL_INVISIBLE 3
bool reconfigure_needed;
spinlock_t lock; /* Protect filters etc */
struct ncsi_package *package;
struct ncsi_channel_version version;
struct ncsi_channel_cap caps[NCSI_CAP_MAX];
struct ncsi_channel_mode modes[NCSI_MODE_MAX];
/* Filtering Settings */
struct ncsi_channel_mac_filter mac_filter;
struct ncsi_channel_vlan_filter vlan_filter;
struct ncsi_channel_stats stats;
struct {
struct timer_list timer;
bool enabled;
unsigned int state;
#define NCSI_CHANNEL_MONITOR_START 0
#define NCSI_CHANNEL_MONITOR_RETRY 1
#define NCSI_CHANNEL_MONITOR_WAIT 2
#define NCSI_CHANNEL_MONITOR_WAIT_MAX 5
} monitor;
struct list_head node;
struct list_head link;
};
struct ncsi_package {
unsigned char id; /* NCSI 3-bits package ID */
unsigned char uuid[16]; /* UUID */
struct ncsi_dev_priv *ndp; /* NCSI device */
spinlock_t lock; /* Protect the package */
unsigned int channel_num; /* Number of channels */
struct list_head channels; /* List of channels */
struct list_head node; /* Form list of packages */
bool multi_channel; /* Enable multiple channels */
u32 channel_whitelist; /* Channels to configure */
struct ncsi_channel *preferred_channel; /* Primary channel */
};
struct ncsi_request {
unsigned char id; /* Request ID - 0 to 255 */
bool used; /* Request that has been assigned */
unsigned int flags; /* NCSI request property */
#define NCSI_REQ_FLAG_EVENT_DRIVEN 1
#define NCSI_REQ_FLAG_NETLINK_DRIVEN 2
struct ncsi_dev_priv *ndp; /* Associated NCSI device */
struct sk_buff *cmd; /* Associated NCSI command packet */
struct sk_buff *rsp; /* Associated NCSI response packet */
struct timer_list timer; /* Timer on waiting for response */
bool enabled; /* Time has been enabled or not */
u32 snd_seq; /* netlink sending sequence number */
u32 snd_portid; /* netlink portid of sender */
struct nlmsghdr nlhdr; /* netlink message header */
};
enum {
ncsi_dev_state_major = 0xff00,
ncsi_dev_state_minor = 0x00ff,
ncsi_dev_state_probe_deselect = 0x0201,
ncsi_dev_state_probe_package,
ncsi_dev_state_probe_channel,
ncsi_dev_state_probe_mlx_gma,
ncsi_dev_state_probe_mlx_smaf,
ncsi_dev_state_probe_cis,
ncsi_dev_state_probe_keep_phy,
ncsi_dev_state_probe_gvi,
ncsi_dev_state_probe_gc,
ncsi_dev_state_probe_gls,
ncsi_dev_state_probe_dp,
ncsi_dev_state_config_sp = 0x0301,
ncsi_dev_state_config_cis,
ncsi_dev_state_config_oem_gma,
ncsi_dev_state_config_apply_mac,
ncsi_dev_state_config_clear_vids,
ncsi_dev_state_config_svf,
ncsi_dev_state_config_ev,
ncsi_dev_state_config_sma,
ncsi_dev_state_config_ebf,
ncsi_dev_state_config_dgmf,
ncsi_dev_state_config_ecnt,
ncsi_dev_state_config_ec,
ncsi_dev_state_config_ae,
ncsi_dev_state_config_gls,
ncsi_dev_state_config_done,
ncsi_dev_state_suspend_select = 0x0401,
ncsi_dev_state_suspend_gls,
ncsi_dev_state_suspend_dcnt,
ncsi_dev_state_suspend_dc,
ncsi_dev_state_suspend_deselect,
ncsi_dev_state_suspend_done
};
struct vlan_vid {
struct list_head list;
__be16 proto;
u16 vid;
};
struct ncsi_dev_priv {
struct ncsi_dev ndev; /* Associated NCSI device */
unsigned int flags; /* NCSI device flags */
#define NCSI_DEV_PROBED 1 /* Finalized NCSI topology */
#define NCSI_DEV_HWA 2 /* Enabled HW arbitration */
#define NCSI_DEV_RESHUFFLE 4
#define NCSI_DEV_RESET 8 /* Reset state of NC */
unsigned int gma_flag; /* OEM GMA flag */
struct sockaddr_storage pending_mac; /* MAC address received from GMA */
spinlock_t lock; /* Protect the NCSI device */
unsigned int package_probe_id;/* Current ID during probe */
unsigned int package_num; /* Number of packages */
unsigned int channel_probe_id;/* Current cahnnel ID during probe */
struct list_head packages; /* List of packages */
struct ncsi_channel *hot_channel; /* Channel was ever active */
struct ncsi_request requests[256]; /* Request table */
unsigned int request_id; /* Last used request ID */
#define NCSI_REQ_START_IDX 1
unsigned int pending_req_num; /* Number of pending requests */
struct ncsi_package *active_package; /* Currently handled package */
struct ncsi_channel *active_channel; /* Currently handled channel */
struct list_head channel_queue; /* Config queue of channels */
struct work_struct work; /* For channel management */
struct packet_type ptype; /* NCSI packet Rx handler */
struct list_head node; /* Form NCSI device list */
#define NCSI_MAX_VLAN_VIDS 15
struct list_head vlan_vids; /* List of active VLAN IDs */
bool multi_package; /* Enable multiple packages */
bool mlx_multi_host; /* Enable multi host Mellanox */
u32 package_whitelist; /* Packages to configure */
unsigned char channel_count; /* Num of channels to probe */
};
struct ncsi_cmd_arg {
struct ncsi_dev_priv *ndp; /* Associated NCSI device */
unsigned char type; /* Command in the NCSI packet */
unsigned char id; /* Request ID (sequence number) */
unsigned char package; /* Destination package ID */
unsigned char channel; /* Destination channel ID or 0x1f */
unsigned short payload; /* Command packet payload length */
unsigned int req_flags; /* NCSI request properties */
union {
unsigned char bytes[16]; /* Command packet specific data */
unsigned short words[8];
unsigned int dwords[4];
};
unsigned char *data; /* NCSI OEM data */
struct genl_info *info; /* Netlink information */
};
extern struct list_head ncsi_dev_list;
extern spinlock_t ncsi_dev_lock;
#define TO_NCSI_DEV_PRIV(nd) \
container_of(nd, struct ncsi_dev_priv, ndev)
#define NCSI_FOR_EACH_DEV(ndp) \
list_for_each_entry_rcu(ndp, &ncsi_dev_list, node)
#define NCSI_FOR_EACH_PACKAGE(ndp, np) \
list_for_each_entry_rcu(np, &ndp->packages, node)
#define NCSI_FOR_EACH_CHANNEL(np, nc) \
list_for_each_entry_rcu(nc, &np->channels, node)
/* Resources */
int ncsi_reset_dev(struct ncsi_dev *nd);
void ncsi_start_channel_monitor(struct ncsi_channel *nc);
void ncsi_stop_channel_monitor(struct ncsi_channel *nc);
struct ncsi_channel *ncsi_find_channel(struct ncsi_package *np,
unsigned char id);
struct ncsi_channel *ncsi_add_channel(struct ncsi_package *np,
unsigned char id);
struct ncsi_package *ncsi_find_package(struct ncsi_dev_priv *ndp,
unsigned char id);
struct ncsi_package *ncsi_add_package(struct ncsi_dev_priv *ndp,
unsigned char id);
void ncsi_remove_package(struct ncsi_package *np);
void ncsi_find_package_and_channel(struct ncsi_dev_priv *ndp,
unsigned char id,
struct ncsi_package **np,
struct ncsi_channel **nc);
struct ncsi_request *ncsi_alloc_request(struct ncsi_dev_priv *ndp,
unsigned int req_flags);
void ncsi_free_request(struct ncsi_request *nr);
struct ncsi_dev *ncsi_find_dev(struct net_device *dev);
int ncsi_process_next_channel(struct ncsi_dev_priv *ndp);
bool ncsi_channel_has_link(struct ncsi_channel *channel);
bool ncsi_channel_is_last(struct ncsi_dev_priv *ndp,
struct ncsi_channel *channel);
int ncsi_update_tx_channel(struct ncsi_dev_priv *ndp,
struct ncsi_package *np,
struct ncsi_channel *disable,
struct ncsi_channel *enable);
/* Packet handlers */
u32 ncsi_calculate_checksum(unsigned char *data, int len);
int ncsi_xmit_cmd(struct ncsi_cmd_arg *nca);
int ncsi_rcv_rsp(struct sk_buff *skb, struct net_device *dev,
struct packet_type *pt, struct net_device *orig_dev);
int ncsi_aen_handler(struct ncsi_dev_priv *ndp, struct sk_buff *skb);
#endif /* __NCSI_INTERNAL_H__ */
+247
View File
@@ -0,0 +1,247 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright Gavin Shan, IBM Corporation 2016.
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/netdevice.h>
#include <linux/skbuff.h>
#include <net/ncsi.h>
#include <net/net_namespace.h>
#include <net/sock.h>
#include "internal.h"
#include "ncsi-pkt.h"
static int ncsi_validate_aen_pkt(struct ncsi_aen_pkt_hdr *h,
const unsigned short payload)
{
u32 checksum;
__be32 *pchecksum;
if (h->common.revision != NCSI_PKT_REVISION)
return -EINVAL;
if (ntohs(h->common.length) != payload)
return -EINVAL;
/* Validate checksum, which might be zeroes if the
* sender doesn't support checksum according to NCSI
* specification.
*/
pchecksum = (__be32 *)((void *)(h + 1) + payload - 4);
if (ntohl(*pchecksum) == 0)
return 0;
checksum = ncsi_calculate_checksum((unsigned char *)h,
sizeof(*h) + payload - 4);
if (*pchecksum != htonl(checksum))
return -EINVAL;
return 0;
}
static int ncsi_aen_handler_lsc(struct ncsi_dev_priv *ndp,
struct ncsi_aen_pkt_hdr *h)
{
struct ncsi_channel *nc, *tmp;
struct ncsi_channel_mode *ncm;
unsigned long old_data, data;
struct ncsi_aen_lsc_pkt *lsc;
struct ncsi_package *np;
bool had_link, has_link;
unsigned long flags;
bool chained;
int state;
/* Find the NCSI channel */
ncsi_find_package_and_channel(ndp, h->common.channel, NULL, &nc);
if (!nc)
return -ENODEV;
/* Update the link status */
lsc = (struct ncsi_aen_lsc_pkt *)h;
spin_lock_irqsave(&nc->lock, flags);
ncm = &nc->modes[NCSI_MODE_LINK];
old_data = ncm->data[2];
data = ntohl(lsc->status);
ncm->data[2] = data;
ncm->data[4] = ntohl(lsc->oem_status);
had_link = !!(old_data & 0x1);
has_link = !!(data & 0x1);
netdev_dbg(ndp->ndev.dev, "NCSI: LSC AEN - channel %u state %s\n",
nc->id, data & 0x1 ? "up" : "down");
chained = !list_empty(&nc->link);
state = nc->state;
spin_unlock_irqrestore(&nc->lock, flags);
if (state == NCSI_CHANNEL_INACTIVE)
netdev_warn(ndp->ndev.dev,
"NCSI: Inactive channel %u received AEN!\n",
nc->id);
if ((had_link == has_link) || chained)
return 0;
if (!ndp->multi_package && !nc->package->multi_channel) {
if (had_link) {
ndp->flags |= NCSI_DEV_RESHUFFLE;
ncsi_stop_channel_monitor(nc);
spin_lock_irqsave(&ndp->lock, flags);
list_add_tail_rcu(&nc->link, &ndp->channel_queue);
spin_unlock_irqrestore(&ndp->lock, flags);
return ncsi_process_next_channel(ndp);
}
/* Configured channel came up */
return 0;
}
if (had_link) {
ncm = &nc->modes[NCSI_MODE_TX_ENABLE];
if (ncsi_channel_is_last(ndp, nc)) {
/* No channels left, reconfigure */
return ncsi_reset_dev(&ndp->ndev);
} else if (ncm->enable) {
/* Need to failover Tx channel */
ncsi_update_tx_channel(ndp, nc->package, nc, NULL);
}
} else if (has_link && nc->package->preferred_channel == nc) {
/* Return Tx to preferred channel */
ncsi_update_tx_channel(ndp, nc->package, NULL, nc);
} else if (has_link) {
NCSI_FOR_EACH_PACKAGE(ndp, np) {
NCSI_FOR_EACH_CHANNEL(np, tmp) {
/* Enable Tx on this channel if the current Tx
* channel is down.
*/
ncm = &tmp->modes[NCSI_MODE_TX_ENABLE];
if (ncm->enable &&
!ncsi_channel_has_link(tmp)) {
ncsi_update_tx_channel(ndp, nc->package,
tmp, nc);
break;
}
}
}
}
/* Leave configured channels active in a multi-channel scenario so
* AEN events are still received.
*/
return 0;
}
static int ncsi_aen_handler_cr(struct ncsi_dev_priv *ndp,
struct ncsi_aen_pkt_hdr *h)
{
struct ncsi_channel *nc;
unsigned long flags;
/* Find the NCSI channel */
ncsi_find_package_and_channel(ndp, h->common.channel, NULL, &nc);
if (!nc)
return -ENODEV;
spin_lock_irqsave(&nc->lock, flags);
if (!list_empty(&nc->link) ||
nc->state != NCSI_CHANNEL_ACTIVE) {
spin_unlock_irqrestore(&nc->lock, flags);
return 0;
}
spin_unlock_irqrestore(&nc->lock, flags);
ncsi_stop_channel_monitor(nc);
spin_lock_irqsave(&nc->lock, flags);
nc->state = NCSI_CHANNEL_INVISIBLE;
spin_unlock_irqrestore(&nc->lock, flags);
spin_lock_irqsave(&ndp->lock, flags);
nc->state = NCSI_CHANNEL_INACTIVE;
list_add_tail_rcu(&nc->link, &ndp->channel_queue);
spin_unlock_irqrestore(&ndp->lock, flags);
nc->modes[NCSI_MODE_TX_ENABLE].enable = 0;
return ncsi_process_next_channel(ndp);
}
static int ncsi_aen_handler_hncdsc(struct ncsi_dev_priv *ndp,
struct ncsi_aen_pkt_hdr *h)
{
struct ncsi_channel *nc;
struct ncsi_channel_mode *ncm;
struct ncsi_aen_hncdsc_pkt *hncdsc;
unsigned long flags;
/* Find the NCSI channel */
ncsi_find_package_and_channel(ndp, h->common.channel, NULL, &nc);
if (!nc)
return -ENODEV;
spin_lock_irqsave(&nc->lock, flags);
ncm = &nc->modes[NCSI_MODE_LINK];
hncdsc = (struct ncsi_aen_hncdsc_pkt *)h;
ncm->data[3] = ntohl(hncdsc->status);
spin_unlock_irqrestore(&nc->lock, flags);
netdev_dbg(ndp->ndev.dev,
"NCSI: host driver %srunning on channel %u\n",
ncm->data[3] & 0x1 ? "" : "not ", nc->id);
return 0;
}
static struct ncsi_aen_handler {
unsigned char type;
int payload;
int (*handler)(struct ncsi_dev_priv *ndp,
struct ncsi_aen_pkt_hdr *h);
} ncsi_aen_handlers[] = {
{ NCSI_PKT_AEN_LSC, 12, ncsi_aen_handler_lsc },
{ NCSI_PKT_AEN_CR, 4, ncsi_aen_handler_cr },
{ NCSI_PKT_AEN_HNCDSC, 8, ncsi_aen_handler_hncdsc }
};
int ncsi_aen_handler(struct ncsi_dev_priv *ndp, struct sk_buff *skb)
{
struct ncsi_aen_pkt_hdr *h;
struct ncsi_aen_handler *nah = NULL;
int i, ret;
/* Find the handler */
h = (struct ncsi_aen_pkt_hdr *)skb_network_header(skb);
for (i = 0; i < ARRAY_SIZE(ncsi_aen_handlers); i++) {
if (ncsi_aen_handlers[i].type == h->type) {
nah = &ncsi_aen_handlers[i];
break;
}
}
if (!nah) {
netdev_warn(ndp->ndev.dev, "Invalid AEN (0x%x) received\n",
h->type);
ret = -ENOENT;
goto out;
}
ret = ncsi_validate_aen_pkt(h, nah->payload);
if (ret) {
netdev_warn(ndp->ndev.dev,
"NCSI: 'bad' packet ignored for AEN type 0x%x\n",
h->type);
goto out;
}
ret = nah->handler(ndp, h);
if (ret)
netdev_err(ndp->ndev.dev,
"NCSI: Handler for AEN type 0x%x returned %d\n",
h->type, ret);
out:
consume_skb(skb);
return ret;
}
+408
View File
@@ -0,0 +1,408 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright Gavin Shan, IBM Corporation 2016.
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/etherdevice.h>
#include <linux/netdevice.h>
#include <linux/skbuff.h>
#include <net/ncsi.h>
#include <net/net_namespace.h>
#include <net/sock.h>
#include <net/genetlink.h>
#include "internal.h"
#include "ncsi-pkt.h"
static const int padding_bytes = 26;
u32 ncsi_calculate_checksum(unsigned char *data, int len)
{
u32 checksum = 0;
int i;
for (i = 0; i < len; i += 2)
checksum += (((u32)data[i] << 8) | data[i + 1]);
checksum = (~checksum + 1);
return checksum;
}
/* This function should be called after the data area has been
* populated completely.
*/
static void ncsi_cmd_build_header(struct ncsi_pkt_hdr *h,
struct ncsi_cmd_arg *nca)
{
u32 checksum;
__be32 *pchecksum;
h->mc_id = 0;
h->revision = NCSI_PKT_REVISION;
h->reserved = 0;
h->id = nca->id;
h->type = nca->type;
h->channel = NCSI_TO_CHANNEL(nca->package,
nca->channel);
h->length = htons(nca->payload);
h->reserved1[0] = 0;
h->reserved1[1] = 0;
/* Fill with calculated checksum */
checksum = ncsi_calculate_checksum((unsigned char *)h,
sizeof(*h) + nca->payload);
pchecksum = (__be32 *)((void *)h + sizeof(struct ncsi_pkt_hdr) +
ALIGN(nca->payload, 4));
*pchecksum = htonl(checksum);
}
static int ncsi_cmd_handler_default(struct sk_buff *skb,
struct ncsi_cmd_arg *nca)
{
struct ncsi_cmd_pkt *cmd;
cmd = skb_put_zero(skb, sizeof(*cmd));
ncsi_cmd_build_header(&cmd->cmd.common, nca);
return 0;
}
static int ncsi_cmd_handler_sp(struct sk_buff *skb,
struct ncsi_cmd_arg *nca)
{
struct ncsi_cmd_sp_pkt *cmd;
cmd = skb_put_zero(skb, sizeof(*cmd));
cmd->hw_arbitration = nca->bytes[0];
ncsi_cmd_build_header(&cmd->cmd.common, nca);
return 0;
}
static int ncsi_cmd_handler_dc(struct sk_buff *skb,
struct ncsi_cmd_arg *nca)
{
struct ncsi_cmd_dc_pkt *cmd;
cmd = skb_put_zero(skb, sizeof(*cmd));
cmd->ald = nca->bytes[0];
ncsi_cmd_build_header(&cmd->cmd.common, nca);
return 0;
}
static int ncsi_cmd_handler_rc(struct sk_buff *skb,
struct ncsi_cmd_arg *nca)
{
struct ncsi_cmd_rc_pkt *cmd;
cmd = skb_put_zero(skb, sizeof(*cmd));
ncsi_cmd_build_header(&cmd->cmd.common, nca);
return 0;
}
static int ncsi_cmd_handler_ae(struct sk_buff *skb,
struct ncsi_cmd_arg *nca)
{
struct ncsi_cmd_ae_pkt *cmd;
cmd = skb_put_zero(skb, sizeof(*cmd));
cmd->mc_id = nca->bytes[0];
cmd->mode = htonl(nca->dwords[1]);
ncsi_cmd_build_header(&cmd->cmd.common, nca);
return 0;
}
static int ncsi_cmd_handler_sl(struct sk_buff *skb,
struct ncsi_cmd_arg *nca)
{
struct ncsi_cmd_sl_pkt *cmd;
cmd = skb_put_zero(skb, sizeof(*cmd));
cmd->mode = htonl(nca->dwords[0]);
cmd->oem_mode = htonl(nca->dwords[1]);
ncsi_cmd_build_header(&cmd->cmd.common, nca);
return 0;
}
static int ncsi_cmd_handler_svf(struct sk_buff *skb,
struct ncsi_cmd_arg *nca)
{
struct ncsi_cmd_svf_pkt *cmd;
cmd = skb_put_zero(skb, sizeof(*cmd));
cmd->vlan = htons(nca->words[1]);
cmd->index = nca->bytes[6];
cmd->enable = nca->bytes[7];
ncsi_cmd_build_header(&cmd->cmd.common, nca);
return 0;
}
static int ncsi_cmd_handler_ev(struct sk_buff *skb,
struct ncsi_cmd_arg *nca)
{
struct ncsi_cmd_ev_pkt *cmd;
cmd = skb_put_zero(skb, sizeof(*cmd));
cmd->mode = nca->bytes[3];
ncsi_cmd_build_header(&cmd->cmd.common, nca);
return 0;
}
static int ncsi_cmd_handler_sma(struct sk_buff *skb,
struct ncsi_cmd_arg *nca)
{
struct ncsi_cmd_sma_pkt *cmd;
int i;
cmd = skb_put_zero(skb, sizeof(*cmd));
for (i = 0; i < 6; i++)
cmd->mac[i] = nca->bytes[i];
cmd->index = nca->bytes[6];
cmd->at_e = nca->bytes[7];
ncsi_cmd_build_header(&cmd->cmd.common, nca);
return 0;
}
static int ncsi_cmd_handler_ebf(struct sk_buff *skb,
struct ncsi_cmd_arg *nca)
{
struct ncsi_cmd_ebf_pkt *cmd;
cmd = skb_put_zero(skb, sizeof(*cmd));
cmd->mode = htonl(nca->dwords[0]);
ncsi_cmd_build_header(&cmd->cmd.common, nca);
return 0;
}
static int ncsi_cmd_handler_egmf(struct sk_buff *skb,
struct ncsi_cmd_arg *nca)
{
struct ncsi_cmd_egmf_pkt *cmd;
cmd = skb_put_zero(skb, sizeof(*cmd));
cmd->mode = htonl(nca->dwords[0]);
ncsi_cmd_build_header(&cmd->cmd.common, nca);
return 0;
}
static int ncsi_cmd_handler_snfc(struct sk_buff *skb,
struct ncsi_cmd_arg *nca)
{
struct ncsi_cmd_snfc_pkt *cmd;
cmd = skb_put_zero(skb, sizeof(*cmd));
cmd->mode = nca->bytes[0];
ncsi_cmd_build_header(&cmd->cmd.common, nca);
return 0;
}
static int ncsi_cmd_handler_oem(struct sk_buff *skb,
struct ncsi_cmd_arg *nca)
{
struct ncsi_cmd_oem_pkt *cmd;
unsigned int len;
int payload;
/* NC-SI spec DSP_0222_1.2.0, section 8.2.2.2
* requires payload to be padded with 0 to
* 32-bit boundary before the checksum field.
* Ensure the padding bytes are accounted for in
* skb allocation
*/
payload = ALIGN(nca->payload, 4);
len = sizeof(struct ncsi_cmd_pkt_hdr) + 4;
len += max(payload, padding_bytes);
cmd = skb_put_zero(skb, len);
unsafe_memcpy(&cmd->mfr_id, nca->data, nca->payload,
/* skb allocated with enough to load the payload */);
ncsi_cmd_build_header(&cmd->cmd.common, nca);
return 0;
}
static struct ncsi_cmd_handler {
unsigned char type;
int payload;
int (*handler)(struct sk_buff *skb,
struct ncsi_cmd_arg *nca);
} ncsi_cmd_handlers[] = {
{ NCSI_PKT_CMD_CIS, 0, ncsi_cmd_handler_default },
{ NCSI_PKT_CMD_SP, 4, ncsi_cmd_handler_sp },
{ NCSI_PKT_CMD_DP, 0, ncsi_cmd_handler_default },
{ NCSI_PKT_CMD_EC, 0, ncsi_cmd_handler_default },
{ NCSI_PKT_CMD_DC, 4, ncsi_cmd_handler_dc },
{ NCSI_PKT_CMD_RC, 4, ncsi_cmd_handler_rc },
{ NCSI_PKT_CMD_ECNT, 0, ncsi_cmd_handler_default },
{ NCSI_PKT_CMD_DCNT, 0, ncsi_cmd_handler_default },
{ NCSI_PKT_CMD_AE, 8, ncsi_cmd_handler_ae },
{ NCSI_PKT_CMD_SL, 8, ncsi_cmd_handler_sl },
{ NCSI_PKT_CMD_GLS, 0, ncsi_cmd_handler_default },
{ NCSI_PKT_CMD_SVF, 8, ncsi_cmd_handler_svf },
{ NCSI_PKT_CMD_EV, 4, ncsi_cmd_handler_ev },
{ NCSI_PKT_CMD_DV, 0, ncsi_cmd_handler_default },
{ NCSI_PKT_CMD_SMA, 8, ncsi_cmd_handler_sma },
{ NCSI_PKT_CMD_EBF, 4, ncsi_cmd_handler_ebf },
{ NCSI_PKT_CMD_DBF, 0, ncsi_cmd_handler_default },
{ NCSI_PKT_CMD_EGMF, 4, ncsi_cmd_handler_egmf },
{ NCSI_PKT_CMD_DGMF, 0, ncsi_cmd_handler_default },
{ NCSI_PKT_CMD_SNFC, 4, ncsi_cmd_handler_snfc },
{ NCSI_PKT_CMD_GVI, 0, ncsi_cmd_handler_default },
{ NCSI_PKT_CMD_GC, 0, ncsi_cmd_handler_default },
{ NCSI_PKT_CMD_GP, 0, ncsi_cmd_handler_default },
{ NCSI_PKT_CMD_GCPS, 0, ncsi_cmd_handler_default },
{ NCSI_PKT_CMD_GNS, 0, ncsi_cmd_handler_default },
{ NCSI_PKT_CMD_GNPTS, 0, ncsi_cmd_handler_default },
{ NCSI_PKT_CMD_GPS, 0, ncsi_cmd_handler_default },
{ NCSI_PKT_CMD_OEM, -1, ncsi_cmd_handler_oem },
{ NCSI_PKT_CMD_PLDM, 0, NULL },
{ NCSI_PKT_CMD_GPUUID, 0, ncsi_cmd_handler_default },
{ NCSI_PKT_CMD_GMCMA, 0, ncsi_cmd_handler_default }
};
static struct ncsi_request *ncsi_alloc_command(struct ncsi_cmd_arg *nca)
{
struct ncsi_dev_priv *ndp = nca->ndp;
struct ncsi_dev *nd = &ndp->ndev;
struct net_device *dev = nd->dev;
int hlen = LL_RESERVED_SPACE(dev);
int tlen = dev->needed_tailroom;
int payload;
int len = hlen + tlen;
struct sk_buff *skb;
struct ncsi_request *nr;
nr = ncsi_alloc_request(ndp, nca->req_flags);
if (!nr)
return NULL;
/* NCSI command packet has 16-bytes header, payload, 4 bytes checksum.
* Payload needs padding so that the checksum field following payload is
* aligned to 32-bit boundary.
* The packet needs padding if its payload is less than 26 bytes to
* meet 64 bytes minimal ethernet frame length.
*/
len += sizeof(struct ncsi_cmd_pkt_hdr) + 4;
payload = ALIGN(nca->payload, 4);
len += max(payload, padding_bytes);
/* Allocate skb */
skb = alloc_skb(len, GFP_ATOMIC);
if (!skb) {
ncsi_free_request(nr);
return NULL;
}
nr->cmd = skb;
skb_reserve(skb, hlen);
skb_reset_network_header(skb);
skb->dev = dev;
skb->protocol = htons(ETH_P_NCSI);
return nr;
}
int ncsi_xmit_cmd(struct ncsi_cmd_arg *nca)
{
struct ncsi_cmd_handler *nch = NULL;
struct ncsi_request *nr;
unsigned char type;
struct ethhdr *eh;
int i, ret;
/* Use OEM generic handler for Netlink request */
if (nca->req_flags == NCSI_REQ_FLAG_NETLINK_DRIVEN)
type = NCSI_PKT_CMD_OEM;
else
type = nca->type;
/* Search for the handler */
for (i = 0; i < ARRAY_SIZE(ncsi_cmd_handlers); i++) {
if (ncsi_cmd_handlers[i].type == type) {
if (ncsi_cmd_handlers[i].handler)
nch = &ncsi_cmd_handlers[i];
else
nch = NULL;
break;
}
}
if (!nch) {
netdev_err(nca->ndp->ndev.dev,
"Cannot send packet with type 0x%02x\n", nca->type);
return -ENOENT;
}
/* Get packet payload length and allocate the request
* It is expected that if length set as negative in
* handler structure means caller is initializing it
* and setting length in nca before calling xmit function
*/
if (nch->payload >= 0)
nca->payload = nch->payload;
nr = ncsi_alloc_command(nca);
if (!nr)
return -ENOMEM;
/* track netlink information */
if (nca->req_flags == NCSI_REQ_FLAG_NETLINK_DRIVEN) {
nr->snd_seq = nca->info->snd_seq;
nr->snd_portid = nca->info->snd_portid;
nr->nlhdr = *nca->info->nlhdr;
}
/* Prepare the packet */
nca->id = nr->id;
ret = nch->handler(nr->cmd, nca);
if (ret) {
ncsi_free_request(nr);
return ret;
}
/* Fill the ethernet header */
eh = skb_push(nr->cmd, sizeof(*eh));
eh->h_proto = htons(ETH_P_NCSI);
eth_broadcast_addr(eh->h_dest);
/* If mac address received from device then use it for
* source address as unicast address else use broadcast
* address as source address
*/
if (nca->ndp->gma_flag == 1)
memcpy(eh->h_source, nca->ndp->ndev.dev->dev_addr, ETH_ALEN);
else
eth_broadcast_addr(eh->h_source);
/* Start the timer for the request that might not have
* corresponding response. Given NCSI is an internal
* connection a 1 second delay should be sufficient.
*/
nr->enabled = true;
mod_timer(&nr->timer, jiffies + 1 * HZ);
/* Send NCSI packet */
skb_get(nr->cmd);
ret = dev_queue_xmit(nr->cmd);
if (ret < 0) {
ncsi_free_request(nr);
return ret;
}
return 0;
}
File diff suppressed because it is too large Load Diff
+782
View File
@@ -0,0 +1,782 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright Samuel Mendoza-Jonas, IBM Corporation 2018.
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/if_arp.h>
#include <linux/rtnetlink.h>
#include <linux/etherdevice.h>
#include <net/genetlink.h>
#include <net/ncsi.h>
#include <linux/skbuff.h>
#include <net/sock.h>
#include <uapi/linux/ncsi.h>
#include "internal.h"
#include "ncsi-pkt.h"
#include "ncsi-netlink.h"
static struct genl_family ncsi_genl_family;
static const struct nla_policy ncsi_genl_policy[NCSI_ATTR_MAX + 1] = {
[NCSI_ATTR_IFINDEX] = { .type = NLA_U32 },
[NCSI_ATTR_PACKAGE_LIST] = { .type = NLA_NESTED },
[NCSI_ATTR_PACKAGE_ID] = { .type = NLA_U32 },
[NCSI_ATTR_CHANNEL_ID] = { .type = NLA_U32 },
[NCSI_ATTR_DATA] = { .type = NLA_BINARY, .len = 2048 },
[NCSI_ATTR_MULTI_FLAG] = { .type = NLA_FLAG },
[NCSI_ATTR_PACKAGE_MASK] = { .type = NLA_U32 },
[NCSI_ATTR_CHANNEL_MASK] = { .type = NLA_U32 },
};
static struct ncsi_dev_priv *ndp_from_ifindex(struct net *net, u32 ifindex)
{
struct ncsi_dev_priv *ndp;
struct net_device *dev;
struct ncsi_dev *nd;
struct ncsi_dev;
if (!net)
return NULL;
dev = dev_get_by_index(net, ifindex);
if (!dev) {
pr_err("NCSI netlink: No device for ifindex %u\n", ifindex);
return NULL;
}
nd = ncsi_find_dev(dev);
ndp = nd ? TO_NCSI_DEV_PRIV(nd) : NULL;
dev_put(dev);
return ndp;
}
static int ncsi_write_channel_info(struct sk_buff *skb,
struct ncsi_dev_priv *ndp,
struct ncsi_channel *nc)
{
struct ncsi_channel_vlan_filter *ncf;
struct ncsi_channel_mode *m;
struct nlattr *vid_nest;
int i;
nla_put_u32(skb, NCSI_CHANNEL_ATTR_ID, nc->id);
m = &nc->modes[NCSI_MODE_LINK];
nla_put_u32(skb, NCSI_CHANNEL_ATTR_LINK_STATE, m->data[2]);
if (nc->state == NCSI_CHANNEL_ACTIVE)
nla_put_flag(skb, NCSI_CHANNEL_ATTR_ACTIVE);
if (nc == nc->package->preferred_channel)
nla_put_flag(skb, NCSI_CHANNEL_ATTR_FORCED);
nla_put_u32(skb, NCSI_CHANNEL_ATTR_VERSION_MAJOR, nc->version.major);
nla_put_u32(skb, NCSI_CHANNEL_ATTR_VERSION_MINOR, nc->version.minor);
nla_put_string(skb, NCSI_CHANNEL_ATTR_VERSION_STR, nc->version.fw_name);
vid_nest = nla_nest_start_noflag(skb, NCSI_CHANNEL_ATTR_VLAN_LIST);
if (!vid_nest)
return -ENOMEM;
ncf = &nc->vlan_filter;
i = -1;
while ((i = find_next_bit((void *)&ncf->bitmap, ncf->n_vids,
i + 1)) < ncf->n_vids) {
if (ncf->vids[i])
nla_put_u16(skb, NCSI_CHANNEL_ATTR_VLAN_ID,
ncf->vids[i]);
}
nla_nest_end(skb, vid_nest);
return 0;
}
static int ncsi_write_package_info(struct sk_buff *skb,
struct ncsi_dev_priv *ndp, unsigned int id)
{
struct nlattr *pnest, *cnest, *nest;
struct ncsi_package *np;
struct ncsi_channel *nc;
bool found;
int rc;
if (id > ndp->package_num - 1) {
netdev_info(ndp->ndev.dev, "NCSI: No package with id %u\n", id);
return -ENODEV;
}
found = false;
NCSI_FOR_EACH_PACKAGE(ndp, np) {
if (np->id != id)
continue;
pnest = nla_nest_start_noflag(skb, NCSI_PKG_ATTR);
if (!pnest)
return -ENOMEM;
rc = nla_put_u32(skb, NCSI_PKG_ATTR_ID, np->id);
if (rc) {
nla_nest_cancel(skb, pnest);
return rc;
}
if ((0x1 << np->id) == ndp->package_whitelist)
nla_put_flag(skb, NCSI_PKG_ATTR_FORCED);
cnest = nla_nest_start_noflag(skb, NCSI_PKG_ATTR_CHANNEL_LIST);
if (!cnest) {
nla_nest_cancel(skb, pnest);
return -ENOMEM;
}
NCSI_FOR_EACH_CHANNEL(np, nc) {
nest = nla_nest_start_noflag(skb, NCSI_CHANNEL_ATTR);
if (!nest) {
nla_nest_cancel(skb, cnest);
nla_nest_cancel(skb, pnest);
return -ENOMEM;
}
rc = ncsi_write_channel_info(skb, ndp, nc);
if (rc) {
nla_nest_cancel(skb, nest);
nla_nest_cancel(skb, cnest);
nla_nest_cancel(skb, pnest);
return rc;
}
nla_nest_end(skb, nest);
}
nla_nest_end(skb, cnest);
nla_nest_end(skb, pnest);
found = true;
}
if (!found)
return -ENODEV;
return 0;
}
static int ncsi_pkg_info_nl(struct sk_buff *msg, struct genl_info *info)
{
struct ncsi_dev_priv *ndp;
unsigned int package_id;
struct sk_buff *skb;
struct nlattr *attr;
void *hdr;
int rc;
if (!info || !info->attrs)
return -EINVAL;
if (!info->attrs[NCSI_ATTR_IFINDEX])
return -EINVAL;
if (!info->attrs[NCSI_ATTR_PACKAGE_ID])
return -EINVAL;
ndp = ndp_from_ifindex(genl_info_net(info),
nla_get_u32(info->attrs[NCSI_ATTR_IFINDEX]));
if (!ndp)
return -ENODEV;
skb = genlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
if (!skb)
return -ENOMEM;
hdr = genlmsg_put(skb, info->snd_portid, info->snd_seq,
&ncsi_genl_family, 0, NCSI_CMD_PKG_INFO);
if (!hdr) {
kfree_skb(skb);
return -EMSGSIZE;
}
package_id = nla_get_u32(info->attrs[NCSI_ATTR_PACKAGE_ID]);
attr = nla_nest_start_noflag(skb, NCSI_ATTR_PACKAGE_LIST);
if (!attr) {
kfree_skb(skb);
return -EMSGSIZE;
}
rc = ncsi_write_package_info(skb, ndp, package_id);
if (rc) {
nla_nest_cancel(skb, attr);
goto err;
}
nla_nest_end(skb, attr);
genlmsg_end(skb, hdr);
return genlmsg_reply(skb, info);
err:
kfree_skb(skb);
return rc;
}
static int ncsi_pkg_info_all_nl(struct sk_buff *skb,
struct netlink_callback *cb)
{
struct nlattr *attrs[NCSI_ATTR_MAX + 1];
struct ncsi_package *np, *package;
struct ncsi_dev_priv *ndp;
unsigned int package_id;
struct nlattr *attr;
void *hdr;
int rc;
rc = genlmsg_parse_deprecated(cb->nlh, &ncsi_genl_family, attrs, NCSI_ATTR_MAX,
ncsi_genl_policy, NULL);
if (rc)
return rc;
if (!attrs[NCSI_ATTR_IFINDEX])
return -EINVAL;
ndp = ndp_from_ifindex(get_net(sock_net(skb->sk)),
nla_get_u32(attrs[NCSI_ATTR_IFINDEX]));
if (!ndp)
return -ENODEV;
package_id = cb->args[0];
package = NULL;
NCSI_FOR_EACH_PACKAGE(ndp, np)
if (np->id == package_id)
package = np;
if (!package)
return 0; /* done */
hdr = genlmsg_put(skb, NETLINK_CB(cb->skb).portid, cb->nlh->nlmsg_seq,
&ncsi_genl_family, NLM_F_MULTI, NCSI_CMD_PKG_INFO);
if (!hdr) {
rc = -EMSGSIZE;
goto err;
}
attr = nla_nest_start_noflag(skb, NCSI_ATTR_PACKAGE_LIST);
if (!attr) {
rc = -EMSGSIZE;
goto err;
}
rc = ncsi_write_package_info(skb, ndp, package->id);
if (rc) {
nla_nest_cancel(skb, attr);
goto err;
}
nla_nest_end(skb, attr);
genlmsg_end(skb, hdr);
cb->args[0] = package_id + 1;
return skb->len;
err:
genlmsg_cancel(skb, hdr);
return rc;
}
static int ncsi_set_interface_nl(struct sk_buff *msg, struct genl_info *info)
{
struct ncsi_package *np, *package;
struct ncsi_channel *nc, *channel;
u32 package_id, channel_id;
struct ncsi_dev_priv *ndp;
unsigned long flags;
if (!info || !info->attrs)
return -EINVAL;
if (!info->attrs[NCSI_ATTR_IFINDEX])
return -EINVAL;
if (!info->attrs[NCSI_ATTR_PACKAGE_ID])
return -EINVAL;
ndp = ndp_from_ifindex(get_net(sock_net(msg->sk)),
nla_get_u32(info->attrs[NCSI_ATTR_IFINDEX]));
if (!ndp)
return -ENODEV;
package_id = nla_get_u32(info->attrs[NCSI_ATTR_PACKAGE_ID]);
package = NULL;
NCSI_FOR_EACH_PACKAGE(ndp, np)
if (np->id == package_id)
package = np;
if (!package) {
/* The user has set a package that does not exist */
return -ERANGE;
}
channel = NULL;
if (info->attrs[NCSI_ATTR_CHANNEL_ID]) {
channel_id = nla_get_u32(info->attrs[NCSI_ATTR_CHANNEL_ID]);
NCSI_FOR_EACH_CHANNEL(package, nc)
if (nc->id == channel_id) {
channel = nc;
break;
}
if (!channel) {
netdev_info(ndp->ndev.dev,
"NCSI: Channel %u does not exist!\n",
channel_id);
return -ERANGE;
}
}
spin_lock_irqsave(&ndp->lock, flags);
ndp->package_whitelist = 0x1 << package->id;
ndp->multi_package = false;
spin_unlock_irqrestore(&ndp->lock, flags);
spin_lock_irqsave(&package->lock, flags);
package->multi_channel = false;
if (channel) {
package->channel_whitelist = 0x1 << channel->id;
package->preferred_channel = channel;
} else {
/* Allow any channel */
package->channel_whitelist = UINT_MAX;
package->preferred_channel = NULL;
}
spin_unlock_irqrestore(&package->lock, flags);
if (channel)
netdev_info(ndp->ndev.dev,
"Set package 0x%x, channel 0x%x as preferred\n",
package_id, channel_id);
else
netdev_info(ndp->ndev.dev, "Set package 0x%x as preferred\n",
package_id);
/* Update channel configuration */
if (!(ndp->flags & NCSI_DEV_RESET))
ncsi_reset_dev(&ndp->ndev);
return 0;
}
static int ncsi_clear_interface_nl(struct sk_buff *msg, struct genl_info *info)
{
struct ncsi_dev_priv *ndp;
struct ncsi_package *np;
unsigned long flags;
if (!info || !info->attrs)
return -EINVAL;
if (!info->attrs[NCSI_ATTR_IFINDEX])
return -EINVAL;
ndp = ndp_from_ifindex(get_net(sock_net(msg->sk)),
nla_get_u32(info->attrs[NCSI_ATTR_IFINDEX]));
if (!ndp)
return -ENODEV;
/* Reset any whitelists and disable multi mode */
spin_lock_irqsave(&ndp->lock, flags);
ndp->package_whitelist = UINT_MAX;
ndp->multi_package = false;
spin_unlock_irqrestore(&ndp->lock, flags);
NCSI_FOR_EACH_PACKAGE(ndp, np) {
spin_lock_irqsave(&np->lock, flags);
np->multi_channel = false;
np->channel_whitelist = UINT_MAX;
np->preferred_channel = NULL;
spin_unlock_irqrestore(&np->lock, flags);
}
netdev_info(ndp->ndev.dev, "NCSI: Cleared preferred package/channel\n");
/* Update channel configuration */
if (!(ndp->flags & NCSI_DEV_RESET))
ncsi_reset_dev(&ndp->ndev);
return 0;
}
static int ncsi_send_cmd_nl(struct sk_buff *msg, struct genl_info *info)
{
struct ncsi_dev_priv *ndp;
struct ncsi_pkt_hdr *hdr;
struct ncsi_cmd_arg nca;
unsigned char *data;
u32 package_id;
u32 channel_id;
int len, ret;
if (!info || !info->attrs) {
ret = -EINVAL;
goto out;
}
if (!info->attrs[NCSI_ATTR_IFINDEX]) {
ret = -EINVAL;
goto out;
}
if (!info->attrs[NCSI_ATTR_PACKAGE_ID]) {
ret = -EINVAL;
goto out;
}
if (!info->attrs[NCSI_ATTR_CHANNEL_ID]) {
ret = -EINVAL;
goto out;
}
if (!info->attrs[NCSI_ATTR_DATA]) {
ret = -EINVAL;
goto out;
}
ndp = ndp_from_ifindex(get_net(sock_net(msg->sk)),
nla_get_u32(info->attrs[NCSI_ATTR_IFINDEX]));
if (!ndp) {
ret = -ENODEV;
goto out;
}
package_id = nla_get_u32(info->attrs[NCSI_ATTR_PACKAGE_ID]);
channel_id = nla_get_u32(info->attrs[NCSI_ATTR_CHANNEL_ID]);
if (package_id >= NCSI_MAX_PACKAGE || channel_id >= NCSI_MAX_CHANNEL) {
ret = -ERANGE;
goto out_netlink;
}
len = nla_len(info->attrs[NCSI_ATTR_DATA]);
if (len < sizeof(struct ncsi_pkt_hdr)) {
netdev_info(ndp->ndev.dev, "NCSI: no command to send %u\n",
package_id);
ret = -EINVAL;
goto out_netlink;
} else {
data = (unsigned char *)nla_data(info->attrs[NCSI_ATTR_DATA]);
}
hdr = (struct ncsi_pkt_hdr *)data;
nca.ndp = ndp;
nca.package = (unsigned char)package_id;
nca.channel = (unsigned char)channel_id;
nca.type = hdr->type;
nca.req_flags = NCSI_REQ_FLAG_NETLINK_DRIVEN;
nca.info = info;
nca.payload = ntohs(hdr->length);
if (nca.payload > len - sizeof(*hdr)) {
ret = -EINVAL;
goto out_netlink;
}
nca.data = data + sizeof(*hdr);
ret = ncsi_xmit_cmd(&nca);
out_netlink:
if (ret != 0) {
netdev_err(ndp->ndev.dev,
"NCSI: Error %d sending command\n",
ret);
ncsi_send_netlink_err(ndp->ndev.dev,
info->snd_seq,
info->snd_portid,
info->nlhdr,
ret);
}
out:
return ret;
}
int ncsi_send_netlink_rsp(struct ncsi_request *nr,
struct ncsi_package *np,
struct ncsi_channel *nc)
{
struct sk_buff *skb;
struct net *net;
void *hdr;
int rc;
net = dev_net(nr->rsp->dev);
skb = genlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC);
if (!skb)
return -ENOMEM;
hdr = genlmsg_put(skb, nr->snd_portid, nr->snd_seq,
&ncsi_genl_family, 0, NCSI_CMD_SEND_CMD);
if (!hdr) {
kfree_skb(skb);
return -EMSGSIZE;
}
nla_put_u32(skb, NCSI_ATTR_IFINDEX, nr->rsp->dev->ifindex);
if (np)
nla_put_u32(skb, NCSI_ATTR_PACKAGE_ID, np->id);
if (nc)
nla_put_u32(skb, NCSI_ATTR_CHANNEL_ID, nc->id);
else
nla_put_u32(skb, NCSI_ATTR_CHANNEL_ID, NCSI_RESERVED_CHANNEL);
rc = nla_put(skb, NCSI_ATTR_DATA, nr->rsp->len, (void *)nr->rsp->data);
if (rc)
goto err;
genlmsg_end(skb, hdr);
return genlmsg_unicast(net, skb, nr->snd_portid);
err:
kfree_skb(skb);
return rc;
}
int ncsi_send_netlink_timeout(struct ncsi_request *nr,
struct ncsi_package *np,
struct ncsi_channel *nc)
{
struct sk_buff *skb;
struct net *net;
void *hdr;
skb = genlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC);
if (!skb)
return -ENOMEM;
hdr = genlmsg_put(skb, nr->snd_portid, nr->snd_seq,
&ncsi_genl_family, 0, NCSI_CMD_SEND_CMD);
if (!hdr) {
kfree_skb(skb);
return -EMSGSIZE;
}
net = dev_net(nr->cmd->dev);
nla_put_u32(skb, NCSI_ATTR_IFINDEX, nr->cmd->dev->ifindex);
if (np)
nla_put_u32(skb, NCSI_ATTR_PACKAGE_ID, np->id);
else
nla_put_u32(skb, NCSI_ATTR_PACKAGE_ID,
NCSI_PACKAGE_INDEX((((struct ncsi_pkt_hdr *)
nr->cmd->data)->channel)));
if (nc)
nla_put_u32(skb, NCSI_ATTR_CHANNEL_ID, nc->id);
else
nla_put_u32(skb, NCSI_ATTR_CHANNEL_ID, NCSI_RESERVED_CHANNEL);
genlmsg_end(skb, hdr);
return genlmsg_unicast(net, skb, nr->snd_portid);
}
int ncsi_send_netlink_err(struct net_device *dev,
u32 snd_seq,
u32 snd_portid,
const struct nlmsghdr *nlhdr,
int err)
{
struct nlmsghdr *nlh;
struct nlmsgerr *nle;
struct sk_buff *skb;
struct net *net;
skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC);
if (!skb)
return -ENOMEM;
net = dev_net(dev);
nlh = nlmsg_put(skb, snd_portid, snd_seq,
NLMSG_ERROR, sizeof(*nle), 0);
nle = (struct nlmsgerr *)nlmsg_data(nlh);
nle->error = err;
memcpy(&nle->msg, nlhdr, sizeof(*nlh));
nlmsg_end(skb, nlh);
return nlmsg_unicast(net->genl_sock, skb, snd_portid);
}
static int ncsi_set_package_mask_nl(struct sk_buff *msg,
struct genl_info *info)
{
struct ncsi_dev_priv *ndp;
unsigned long flags;
int rc;
if (!info || !info->attrs)
return -EINVAL;
if (!info->attrs[NCSI_ATTR_IFINDEX])
return -EINVAL;
if (!info->attrs[NCSI_ATTR_PACKAGE_MASK])
return -EINVAL;
ndp = ndp_from_ifindex(get_net(sock_net(msg->sk)),
nla_get_u32(info->attrs[NCSI_ATTR_IFINDEX]));
if (!ndp)
return -ENODEV;
spin_lock_irqsave(&ndp->lock, flags);
if (nla_get_flag(info->attrs[NCSI_ATTR_MULTI_FLAG])) {
if (ndp->flags & NCSI_DEV_HWA) {
ndp->multi_package = true;
rc = 0;
} else {
netdev_err(ndp->ndev.dev,
"NCSI: Can't use multiple packages without HWA\n");
rc = -EPERM;
}
} else {
ndp->multi_package = false;
rc = 0;
}
if (!rc)
ndp->package_whitelist =
nla_get_u32(info->attrs[NCSI_ATTR_PACKAGE_MASK]);
spin_unlock_irqrestore(&ndp->lock, flags);
if (!rc) {
/* Update channel configuration */
if (!(ndp->flags & NCSI_DEV_RESET))
ncsi_reset_dev(&ndp->ndev);
}
return rc;
}
static int ncsi_set_channel_mask_nl(struct sk_buff *msg,
struct genl_info *info)
{
struct ncsi_package *np, *package;
struct ncsi_channel *nc, *channel;
u32 package_id, channel_id;
struct ncsi_dev_priv *ndp;
unsigned long flags;
if (!info || !info->attrs)
return -EINVAL;
if (!info->attrs[NCSI_ATTR_IFINDEX])
return -EINVAL;
if (!info->attrs[NCSI_ATTR_PACKAGE_ID])
return -EINVAL;
if (!info->attrs[NCSI_ATTR_CHANNEL_MASK])
return -EINVAL;
ndp = ndp_from_ifindex(get_net(sock_net(msg->sk)),
nla_get_u32(info->attrs[NCSI_ATTR_IFINDEX]));
if (!ndp)
return -ENODEV;
package_id = nla_get_u32(info->attrs[NCSI_ATTR_PACKAGE_ID]);
package = NULL;
NCSI_FOR_EACH_PACKAGE(ndp, np)
if (np->id == package_id) {
package = np;
break;
}
if (!package)
return -ERANGE;
spin_lock_irqsave(&package->lock, flags);
channel = NULL;
if (info->attrs[NCSI_ATTR_CHANNEL_ID]) {
channel_id = nla_get_u32(info->attrs[NCSI_ATTR_CHANNEL_ID]);
NCSI_FOR_EACH_CHANNEL(np, nc)
if (nc->id == channel_id) {
channel = nc;
break;
}
if (!channel) {
spin_unlock_irqrestore(&package->lock, flags);
return -ERANGE;
}
netdev_dbg(ndp->ndev.dev,
"NCSI: Channel %u set as preferred channel\n",
channel->id);
}
package->channel_whitelist =
nla_get_u32(info->attrs[NCSI_ATTR_CHANNEL_MASK]);
if (package->channel_whitelist == 0)
netdev_dbg(ndp->ndev.dev,
"NCSI: Package %u set to all channels disabled\n",
package->id);
package->preferred_channel = channel;
if (nla_get_flag(info->attrs[NCSI_ATTR_MULTI_FLAG])) {
package->multi_channel = true;
netdev_info(ndp->ndev.dev,
"NCSI: Multi-channel enabled on package %u\n",
package_id);
} else {
package->multi_channel = false;
}
spin_unlock_irqrestore(&package->lock, flags);
/* Update channel configuration */
if (!(ndp->flags & NCSI_DEV_RESET))
ncsi_reset_dev(&ndp->ndev);
return 0;
}
static const struct genl_small_ops ncsi_ops[] = {
{
.cmd = NCSI_CMD_PKG_INFO,
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
.doit = ncsi_pkg_info_nl,
.dumpit = ncsi_pkg_info_all_nl,
.flags = 0,
},
{
.cmd = NCSI_CMD_SET_INTERFACE,
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
.doit = ncsi_set_interface_nl,
.flags = GENL_ADMIN_PERM,
},
{
.cmd = NCSI_CMD_CLEAR_INTERFACE,
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
.doit = ncsi_clear_interface_nl,
.flags = GENL_ADMIN_PERM,
},
{
.cmd = NCSI_CMD_SEND_CMD,
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
.doit = ncsi_send_cmd_nl,
.flags = GENL_ADMIN_PERM,
},
{
.cmd = NCSI_CMD_SET_PACKAGE_MASK,
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
.doit = ncsi_set_package_mask_nl,
.flags = GENL_ADMIN_PERM,
},
{
.cmd = NCSI_CMD_SET_CHANNEL_MASK,
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
.doit = ncsi_set_channel_mask_nl,
.flags = GENL_ADMIN_PERM,
},
};
static struct genl_family ncsi_genl_family __ro_after_init = {
.name = "NCSI",
.version = 0,
.maxattr = NCSI_ATTR_MAX,
.policy = ncsi_genl_policy,
.module = THIS_MODULE,
.small_ops = ncsi_ops,
.n_small_ops = ARRAY_SIZE(ncsi_ops),
.resv_start_op = NCSI_CMD_SET_CHANNEL_MASK + 1,
};
static int __init ncsi_init_netlink(void)
{
return genl_register_family(&ncsi_genl_family);
}
subsys_initcall(ncsi_init_netlink);
+25
View File
@@ -0,0 +1,25 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* Copyright Samuel Mendoza-Jonas, IBM Corporation 2018.
*/
#ifndef __NCSI_NETLINK_H__
#define __NCSI_NETLINK_H__
#include <linux/netdevice.h>
#include "internal.h"
int ncsi_send_netlink_rsp(struct ncsi_request *nr,
struct ncsi_package *np,
struct ncsi_channel *nc);
int ncsi_send_netlink_timeout(struct ncsi_request *nr,
struct ncsi_package *np,
struct ncsi_channel *nc);
int ncsi_send_netlink_err(struct net_device *dev,
u32 snd_seq,
u32 snd_portid,
const struct nlmsghdr *nlhdr,
int err);
#endif /* __NCSI_NETLINK_H__ */
+465
View File
@@ -0,0 +1,465 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* Copyright Gavin Shan, IBM Corporation 2016.
*/
#ifndef __NCSI_PKT_H__
#define __NCSI_PKT_H__
struct ncsi_pkt_hdr {
unsigned char mc_id; /* Management controller ID */
unsigned char revision; /* NCSI version - 0x01 */
unsigned char reserved; /* Reserved */
unsigned char id; /* Packet sequence number */
unsigned char type; /* Packet type */
unsigned char channel; /* Network controller ID */
__be16 length; /* Payload length */
__be32 reserved1[2]; /* Reserved */
};
struct ncsi_cmd_pkt_hdr {
struct ncsi_pkt_hdr common; /* Common NCSI packet header */
};
struct ncsi_rsp_pkt_hdr {
struct ncsi_pkt_hdr common; /* Common NCSI packet header */
__be16 code; /* Response code */
__be16 reason; /* Response reason */
};
struct ncsi_aen_pkt_hdr {
struct ncsi_pkt_hdr common; /* Common NCSI packet header */
unsigned char reserved2[3]; /* Reserved */
unsigned char type; /* AEN packet type */
};
/* NCSI common command packet */
struct ncsi_cmd_pkt {
struct ncsi_cmd_pkt_hdr cmd; /* Command header */
__be32 checksum; /* Checksum */
unsigned char pad[26];
};
struct ncsi_rsp_pkt {
struct ncsi_rsp_pkt_hdr rsp; /* Response header */
__be32 checksum; /* Checksum */
unsigned char pad[22];
};
/* Select Package */
struct ncsi_cmd_sp_pkt {
struct ncsi_cmd_pkt_hdr cmd; /* Command header */
unsigned char reserved[3]; /* Reserved */
unsigned char hw_arbitration; /* HW arbitration */
__be32 checksum; /* Checksum */
unsigned char pad[22];
};
/* Disable Channel */
struct ncsi_cmd_dc_pkt {
struct ncsi_cmd_pkt_hdr cmd; /* Command header */
unsigned char reserved[3]; /* Reserved */
unsigned char ald; /* Allow link down */
__be32 checksum; /* Checksum */
unsigned char pad[22];
};
/* Reset Channel */
struct ncsi_cmd_rc_pkt {
struct ncsi_cmd_pkt_hdr cmd; /* Command header */
__be32 reserved; /* Reserved */
__be32 checksum; /* Checksum */
unsigned char pad[22];
};
/* AEN Enable */
struct ncsi_cmd_ae_pkt {
struct ncsi_cmd_pkt_hdr cmd; /* Command header */
unsigned char reserved[3]; /* Reserved */
unsigned char mc_id; /* MC ID */
__be32 mode; /* AEN working mode */
__be32 checksum; /* Checksum */
unsigned char pad[18];
};
/* Set Link */
struct ncsi_cmd_sl_pkt {
struct ncsi_cmd_pkt_hdr cmd; /* Command header */
__be32 mode; /* Link working mode */
__be32 oem_mode; /* OEM link mode */
__be32 checksum; /* Checksum */
unsigned char pad[18];
};
/* Set VLAN Filter */
struct ncsi_cmd_svf_pkt {
struct ncsi_cmd_pkt_hdr cmd; /* Command header */
__be16 reserved; /* Reserved */
__be16 vlan; /* VLAN ID */
__be16 reserved1; /* Reserved */
unsigned char index; /* VLAN table index */
unsigned char enable; /* Enable or disable */
__be32 checksum; /* Checksum */
unsigned char pad[18];
};
/* Enable VLAN */
struct ncsi_cmd_ev_pkt {
struct ncsi_cmd_pkt_hdr cmd; /* Command header */
unsigned char reserved[3]; /* Reserved */
unsigned char mode; /* VLAN filter mode */
__be32 checksum; /* Checksum */
unsigned char pad[22];
};
/* Set MAC Address */
struct ncsi_cmd_sma_pkt {
struct ncsi_cmd_pkt_hdr cmd; /* Command header */
unsigned char mac[6]; /* MAC address */
unsigned char index; /* MAC table index */
unsigned char at_e; /* Addr type and operation */
__be32 checksum; /* Checksum */
unsigned char pad[18];
};
/* Enable Broadcast Filter */
struct ncsi_cmd_ebf_pkt {
struct ncsi_cmd_pkt_hdr cmd; /* Command header */
__be32 mode; /* Filter mode */
__be32 checksum; /* Checksum */
unsigned char pad[22];
};
/* Enable Global Multicast Filter */
struct ncsi_cmd_egmf_pkt {
struct ncsi_cmd_pkt_hdr cmd; /* Command header */
__be32 mode; /* Global MC mode */
__be32 checksum; /* Checksum */
unsigned char pad[22];
};
/* Set NCSI Flow Control */
struct ncsi_cmd_snfc_pkt {
struct ncsi_cmd_pkt_hdr cmd; /* Command header */
unsigned char reserved[3]; /* Reserved */
unsigned char mode; /* Flow control mode */
__be32 checksum; /* Checksum */
unsigned char pad[22];
};
/* OEM Request Command as per NCSI Specification */
struct ncsi_cmd_oem_pkt {
struct ncsi_cmd_pkt_hdr cmd; /* Command header */
__be32 mfr_id; /* Manufacture ID */
unsigned char data[]; /* OEM Payload Data */
};
/* OEM Response Packet as per NCSI Specification */
struct ncsi_rsp_oem_pkt {
struct ncsi_rsp_pkt_hdr rsp; /* Command header */
__be32 mfr_id; /* Manufacture ID */
unsigned char data[]; /* Payload data */
};
/* Mellanox Response Data */
struct ncsi_rsp_oem_mlx_pkt {
unsigned char cmd_rev; /* Command Revision */
unsigned char cmd; /* Command ID */
unsigned char param; /* Parameter */
unsigned char optional; /* Optional data */
unsigned char data[]; /* Data */
};
/* Broadcom Response Data */
struct ncsi_rsp_oem_bcm_pkt {
unsigned char ver; /* Payload Version */
unsigned char type; /* OEM Command type */
__be16 len; /* Payload Length */
unsigned char data[]; /* Cmd specific Data */
};
/* Intel Response Data */
struct ncsi_rsp_oem_intel_pkt {
unsigned char cmd; /* OEM Command ID */
unsigned char data[]; /* Cmd specific Data */
};
/* Get Link Status */
struct ncsi_rsp_gls_pkt {
struct ncsi_rsp_pkt_hdr rsp; /* Response header */
__be32 status; /* Link status */
__be32 other; /* Other indications */
__be32 oem_status; /* OEM link status */
__be32 checksum;
unsigned char pad[10];
};
/* Get Version ID */
struct ncsi_rsp_gvi_pkt {
struct ncsi_rsp_pkt_hdr rsp; /* Response header */
unsigned char major; /* NCSI version major */
unsigned char minor; /* NCSI version minor */
unsigned char update; /* NCSI version update */
unsigned char alpha1; /* NCSI version alpha1 */
unsigned char reserved[3]; /* Reserved */
unsigned char alpha2; /* NCSI version alpha2 */
unsigned char fw_name[12]; /* f/w name string */
__be32 fw_version; /* f/w version */
__be16 pci_ids[4]; /* PCI IDs */
__be32 mf_id; /* Manufacture ID */
__be32 checksum;
};
/* Get Capabilities */
struct ncsi_rsp_gc_pkt {
struct ncsi_rsp_pkt_hdr rsp; /* Response header */
__be32 cap; /* Capabilities */
__be32 bc_cap; /* Broadcast cap */
__be32 mc_cap; /* Multicast cap */
__be32 buf_cap; /* Buffering cap */
__be32 aen_cap; /* AEN cap */
unsigned char vlan_cnt; /* VLAN filter count */
unsigned char mixed_cnt; /* Mix filter count */
unsigned char mc_cnt; /* MC filter count */
unsigned char uc_cnt; /* UC filter count */
unsigned char reserved[2]; /* Reserved */
unsigned char vlan_mode; /* VLAN mode */
unsigned char channel_cnt; /* Channel count */
__be32 checksum; /* Checksum */
};
/* Get Parameters */
struct ncsi_rsp_gp_pkt {
struct ncsi_rsp_pkt_hdr rsp; /* Response header */
unsigned char mac_cnt; /* Number of MAC addr */
unsigned char reserved[2]; /* Reserved */
unsigned char mac_enable; /* MAC addr enable flags */
unsigned char vlan_cnt; /* VLAN tag count */
unsigned char reserved1; /* Reserved */
__be16 vlan_enable; /* VLAN tag enable flags */
__be32 link_mode; /* Link setting */
__be32 bc_mode; /* BC filter mode */
__be32 valid_modes; /* Valid mode parameters */
unsigned char vlan_mode; /* VLAN mode */
unsigned char fc_mode; /* Flow control mode */
unsigned char reserved2[2]; /* Reserved */
__be32 aen_mode; /* AEN mode */
unsigned char mac[6]; /* Supported MAC addr */
__be16 vlan; /* Supported VLAN tags */
__be32 checksum; /* Checksum */
};
/* Get Controller Packet Statistics */
struct ncsi_rsp_gcps_pkt {
struct ncsi_rsp_pkt_hdr rsp; /* Response header */
__be64 cnt; /* Counter cleared */
__be64 rx_bytes; /* Rx bytes */
__be64 tx_bytes; /* Tx bytes */
__be64 rx_uc_pkts; /* Rx UC packets */
__be64 rx_mc_pkts; /* Rx MC packets */
__be64 rx_bc_pkts; /* Rx BC packets */
__be64 tx_uc_pkts; /* Tx UC packets */
__be64 tx_mc_pkts; /* Tx MC packets */
__be64 tx_bc_pkts; /* Tx BC packets */
__be32 fcs_err; /* FCS errors */
__be32 align_err; /* Alignment errors */
__be32 false_carrier; /* False carrier detection */
__be32 runt_pkts; /* Rx runt packets */
__be32 jabber_pkts; /* Rx jabber packets */
__be32 rx_pause_xon; /* Rx pause XON frames */
__be32 rx_pause_xoff; /* Rx XOFF frames */
__be32 tx_pause_xon; /* Tx XON frames */
__be32 tx_pause_xoff; /* Tx XOFF frames */
__be32 tx_s_collision; /* Single collision frames */
__be32 tx_m_collision; /* Multiple collision frames */
__be32 l_collision; /* Late collision frames */
__be32 e_collision; /* Excessive collision frames */
__be32 rx_ctl_frames; /* Rx control frames */
__be32 rx_64_frames; /* Rx 64-bytes frames */
__be32 rx_127_frames; /* Rx 65-127 bytes frames */
__be32 rx_255_frames; /* Rx 128-255 bytes frames */
__be32 rx_511_frames; /* Rx 256-511 bytes frames */
__be32 rx_1023_frames; /* Rx 512-1023 bytes frames */
__be32 rx_1522_frames; /* Rx 1024-1522 bytes frames */
__be32 rx_9022_frames; /* Rx 1523-9022 bytes frames */
__be32 tx_64_frames; /* Tx 64-bytes frames */
__be32 tx_127_frames; /* Tx 65-127 bytes frames */
__be32 tx_255_frames; /* Tx 128-255 bytes frames */
__be32 tx_511_frames; /* Tx 256-511 bytes frames */
__be32 tx_1023_frames; /* Tx 512-1023 bytes frames */
__be32 tx_1522_frames; /* Tx 1024-1522 bytes frames */
__be32 tx_9022_frames; /* Tx 1523-9022 bytes frames */
__be64 rx_valid_bytes; /* Rx valid bytes */
__be32 rx_runt_pkts; /* Rx error runt packets */
__be32 rx_jabber_pkts; /* Rx error jabber packets */
__be32 checksum; /* Checksum */
} __packed __aligned(4);
/* Get NCSI Statistics */
struct ncsi_rsp_gns_pkt {
struct ncsi_rsp_pkt_hdr rsp; /* Response header */
__be32 rx_cmds; /* Rx NCSI commands */
__be32 dropped_cmds; /* Dropped commands */
__be32 cmd_type_errs; /* Command type errors */
__be32 cmd_csum_errs; /* Command checksum errors */
__be32 rx_pkts; /* Rx NCSI packets */
__be32 tx_pkts; /* Tx NCSI packets */
__be32 tx_aen_pkts; /* Tx AEN packets */
__be32 checksum; /* Checksum */
};
/* Get NCSI Pass-through Statistics */
struct ncsi_rsp_gnpts_pkt {
struct ncsi_rsp_pkt_hdr rsp; /* Response header */
__be32 tx_pkts; /* Tx packets */
__be32 tx_dropped; /* Tx dropped packets */
__be32 tx_channel_err; /* Tx channel errors */
__be32 tx_us_err; /* Tx undersize errors */
__be32 rx_pkts; /* Rx packets */
__be32 rx_dropped; /* Rx dropped packets */
__be32 rx_channel_err; /* Rx channel errors */
__be32 rx_us_err; /* Rx undersize errors */
__be32 rx_os_err; /* Rx oversize errors */
__be32 checksum; /* Checksum */
};
/* Get package status */
struct ncsi_rsp_gps_pkt {
struct ncsi_rsp_pkt_hdr rsp; /* Response header */
__be32 status; /* Hardware arbitration status */
__be32 checksum;
};
/* Get package UUID */
struct ncsi_rsp_gpuuid_pkt {
struct ncsi_rsp_pkt_hdr rsp; /* Response header */
unsigned char uuid[16]; /* UUID */
__be32 checksum;
};
/* Get MC MAC Address */
struct ncsi_rsp_gmcma_pkt {
struct ncsi_rsp_pkt_hdr rsp;
unsigned char address_count;
unsigned char reserved[3];
unsigned char addresses[][ETH_ALEN];
};
/* AEN: Link State Change */
struct ncsi_aen_lsc_pkt {
struct ncsi_aen_pkt_hdr aen; /* AEN header */
__be32 status; /* Link status */
__be32 oem_status; /* OEM link status */
__be32 checksum; /* Checksum */
unsigned char pad[14];
};
/* AEN: Configuration Required */
struct ncsi_aen_cr_pkt {
struct ncsi_aen_pkt_hdr aen; /* AEN header */
__be32 checksum; /* Checksum */
unsigned char pad[22];
};
/* AEN: Host Network Controller Driver Status Change */
struct ncsi_aen_hncdsc_pkt {
struct ncsi_aen_pkt_hdr aen; /* AEN header */
__be32 status; /* Status */
__be32 checksum; /* Checksum */
unsigned char pad[18];
};
/* NCSI packet revision */
#define NCSI_PKT_REVISION 0x01
/* NCSI packet commands */
#define NCSI_PKT_CMD_CIS 0x00 /* Clear Initial State */
#define NCSI_PKT_CMD_SP 0x01 /* Select Package */
#define NCSI_PKT_CMD_DP 0x02 /* Deselect Package */
#define NCSI_PKT_CMD_EC 0x03 /* Enable Channel */
#define NCSI_PKT_CMD_DC 0x04 /* Disable Channel */
#define NCSI_PKT_CMD_RC 0x05 /* Reset Channel */
#define NCSI_PKT_CMD_ECNT 0x06 /* Enable Channel Network Tx */
#define NCSI_PKT_CMD_DCNT 0x07 /* Disable Channel Network Tx */
#define NCSI_PKT_CMD_AE 0x08 /* AEN Enable */
#define NCSI_PKT_CMD_SL 0x09 /* Set Link */
#define NCSI_PKT_CMD_GLS 0x0a /* Get Link */
#define NCSI_PKT_CMD_SVF 0x0b /* Set VLAN Filter */
#define NCSI_PKT_CMD_EV 0x0c /* Enable VLAN */
#define NCSI_PKT_CMD_DV 0x0d /* Disable VLAN */
#define NCSI_PKT_CMD_SMA 0x0e /* Set MAC address */
#define NCSI_PKT_CMD_EBF 0x10 /* Enable Broadcast Filter */
#define NCSI_PKT_CMD_DBF 0x11 /* Disable Broadcast Filter */
#define NCSI_PKT_CMD_EGMF 0x12 /* Enable Global Multicast Filter */
#define NCSI_PKT_CMD_DGMF 0x13 /* Disable Global Multicast Filter */
#define NCSI_PKT_CMD_SNFC 0x14 /* Set NCSI Flow Control */
#define NCSI_PKT_CMD_GVI 0x15 /* Get Version ID */
#define NCSI_PKT_CMD_GC 0x16 /* Get Capabilities */
#define NCSI_PKT_CMD_GP 0x17 /* Get Parameters */
#define NCSI_PKT_CMD_GCPS 0x18 /* Get Controller Packet Statistics */
#define NCSI_PKT_CMD_GNS 0x19 /* Get NCSI Statistics */
#define NCSI_PKT_CMD_GNPTS 0x1a /* Get NCSI Pass-throu Statistics */
#define NCSI_PKT_CMD_GPS 0x1b /* Get package status */
#define NCSI_PKT_CMD_OEM 0x50 /* OEM */
#define NCSI_PKT_CMD_PLDM 0x51 /* PLDM request over NCSI over RBT */
#define NCSI_PKT_CMD_GPUUID 0x52 /* Get package UUID */
#define NCSI_PKT_CMD_QPNPR 0x56 /* Query Pending NC PLDM request */
#define NCSI_PKT_CMD_SNPR 0x57 /* Send NC PLDM Reply */
#define NCSI_PKT_CMD_GMCMA 0x58 /* Get MC MAC Address */
/* NCSI packet responses */
#define NCSI_PKT_RSP_CIS (NCSI_PKT_CMD_CIS + 0x80)
#define NCSI_PKT_RSP_SP (NCSI_PKT_CMD_SP + 0x80)
#define NCSI_PKT_RSP_DP (NCSI_PKT_CMD_DP + 0x80)
#define NCSI_PKT_RSP_EC (NCSI_PKT_CMD_EC + 0x80)
#define NCSI_PKT_RSP_DC (NCSI_PKT_CMD_DC + 0x80)
#define NCSI_PKT_RSP_RC (NCSI_PKT_CMD_RC + 0x80)
#define NCSI_PKT_RSP_ECNT (NCSI_PKT_CMD_ECNT + 0x80)
#define NCSI_PKT_RSP_DCNT (NCSI_PKT_CMD_DCNT + 0x80)
#define NCSI_PKT_RSP_AE (NCSI_PKT_CMD_AE + 0x80)
#define NCSI_PKT_RSP_SL (NCSI_PKT_CMD_SL + 0x80)
#define NCSI_PKT_RSP_GLS (NCSI_PKT_CMD_GLS + 0x80)
#define NCSI_PKT_RSP_SVF (NCSI_PKT_CMD_SVF + 0x80)
#define NCSI_PKT_RSP_EV (NCSI_PKT_CMD_EV + 0x80)
#define NCSI_PKT_RSP_DV (NCSI_PKT_CMD_DV + 0x80)
#define NCSI_PKT_RSP_SMA (NCSI_PKT_CMD_SMA + 0x80)
#define NCSI_PKT_RSP_EBF (NCSI_PKT_CMD_EBF + 0x80)
#define NCSI_PKT_RSP_DBF (NCSI_PKT_CMD_DBF + 0x80)
#define NCSI_PKT_RSP_EGMF (NCSI_PKT_CMD_EGMF + 0x80)
#define NCSI_PKT_RSP_DGMF (NCSI_PKT_CMD_DGMF + 0x80)
#define NCSI_PKT_RSP_SNFC (NCSI_PKT_CMD_SNFC + 0x80)
#define NCSI_PKT_RSP_GVI (NCSI_PKT_CMD_GVI + 0x80)
#define NCSI_PKT_RSP_GC (NCSI_PKT_CMD_GC + 0x80)
#define NCSI_PKT_RSP_GP (NCSI_PKT_CMD_GP + 0x80)
#define NCSI_PKT_RSP_GCPS (NCSI_PKT_CMD_GCPS + 0x80)
#define NCSI_PKT_RSP_GNS (NCSI_PKT_CMD_GNS + 0x80)
#define NCSI_PKT_RSP_GNPTS (NCSI_PKT_CMD_GNPTS + 0x80)
#define NCSI_PKT_RSP_GPS (NCSI_PKT_CMD_GPS + 0x80)
#define NCSI_PKT_RSP_OEM (NCSI_PKT_CMD_OEM + 0x80)
#define NCSI_PKT_RSP_PLDM (NCSI_PKT_CMD_PLDM + 0x80)
#define NCSI_PKT_RSP_GPUUID (NCSI_PKT_CMD_GPUUID + 0x80)
#define NCSI_PKT_RSP_QPNPR (NCSI_PKT_CMD_QPNPR + 0x80)
#define NCSI_PKT_RSP_SNPR (NCSI_PKT_CMD_SNPR + 0x80)
#define NCSI_PKT_RSP_GMCMA (NCSI_PKT_CMD_GMCMA + 0x80)
/* NCSI response code/reason */
#define NCSI_PKT_RSP_C_COMPLETED 0x0000 /* Command Completed */
#define NCSI_PKT_RSP_C_FAILED 0x0001 /* Command Failed */
#define NCSI_PKT_RSP_C_UNAVAILABLE 0x0002 /* Command Unavailable */
#define NCSI_PKT_RSP_C_UNSUPPORTED 0x0003 /* Command Unsupported */
#define NCSI_PKT_RSP_R_NO_ERROR 0x0000 /* No Error */
#define NCSI_PKT_RSP_R_INTERFACE 0x0001 /* Interface not ready */
#define NCSI_PKT_RSP_R_PARAM 0x0002 /* Invalid Parameter */
#define NCSI_PKT_RSP_R_CHANNEL 0x0003 /* Channel not Ready */
#define NCSI_PKT_RSP_R_PACKAGE 0x0004 /* Package not Ready */
#define NCSI_PKT_RSP_R_LENGTH 0x0005 /* Invalid payload length */
#define NCSI_PKT_RSP_R_UNKNOWN 0x7fff /* Command type unsupported */
/* NCSI AEN packet type */
#define NCSI_PKT_AEN 0xFF /* AEN Packet */
#define NCSI_PKT_AEN_LSC 0x00 /* Link status change */
#define NCSI_PKT_AEN_CR 0x01 /* Configuration required */
#define NCSI_PKT_AEN_HNCDSC 0x02 /* HNC driver status change */
#endif /* __NCSI_PKT_H__ */
File diff suppressed because it is too large Load Diff