提交 cfcbe858 编写于 作者: D David S. Miller

Merge branch 'mlxsw'

Jiri Pirko says:

====================
Introduce Mellanox Technologies Switch ASICs switchdev drivers

This patchset introduces Mellanox Technologies Switch driver infrastructure
and support for SwitchX-2 ASIC.

The driver is divided into 3 logical parts:
1) Bus - implements switch bus interface. Currently only PCI bus is
   implemented, but more buses will be added in the future. Namely I2C
   and SGMII.
   (patch #2)
2) Driver - implemements of ASIC-specific functions.
   Currently SwitchX-2 ASIC is supported, but a plan exists to introduce
   support for Spectrum ASIC in the near future.
   (patch #4)
3) Core - infrastructure that glues buses and drivers together.
   It implements register access logic (EMADs) and takes care of RX traps
   and events.
   (patch #1 and #3)
====================
Signed-off-by: NDavid S. Miller <davem@davemloft.net>
......@@ -6645,6 +6645,15 @@ W: http://www.mellanox.com
Q: http://patchwork.ozlabs.org/project/netdev/list/
F: drivers/net/ethernet/mellanox/mlx4/en_*
MELLANOX ETHERNET SWITCH DRIVERS
M: Jiri Pirko <jiri@mellanox.com>
M: Ido Schimmel <idosch@mellanox.com>
L: netdev@vger.kernel.org
S: Supported
W: http://www.mellanox.com
Q: http://patchwork.ozlabs.org/project/netdev/list/
F: drivers/net/ethernet/mellanox/mlxsw/
MEMORY MANAGEMENT
L: linux-mm@kvack.org
W: http://www.linux-mm.org
......
......@@ -18,5 +18,6 @@ if NET_VENDOR_MELLANOX
source "drivers/net/ethernet/mellanox/mlx4/Kconfig"
source "drivers/net/ethernet/mellanox/mlx5/core/Kconfig"
source "drivers/net/ethernet/mellanox/mlxsw/Kconfig"
endif # NET_VENDOR_MELLANOX
......@@ -4,3 +4,4 @@
obj-$(CONFIG_MLX4_CORE) += mlx4/
obj-$(CONFIG_MLX5_CORE) += mlx5/core/
obj-$(CONFIG_MLXSW_CORE) += mlxsw/
#
# Mellanox switch drivers configuration
#
config MLXSW_CORE
tristate "Mellanox Technologies Switch ASICs support"
---help---
This driver supports Mellanox Technologies Switch ASICs family.
To compile this driver as a module, choose M here: the
module will be called mlxsw_core.
config MLXSW_PCI
tristate "PCI bus implementation for Mellanox Technologies Switch ASICs"
depends on PCI && MLXSW_CORE
default m
---help---
This is PCI bus implementation for Mellanox Technologies Switch ASICs.
To compile this driver as a module, choose M here: the
module will be called mlxsw_pci.
config MLXSW_SWITCHX2
tristate "Mellanox Technologies SwitchX-2 support"
depends on MLXSW_CORE && NET_SWITCHDEV
default m
---help---
This driver supports Mellanox Technologies SwitchX-2 Ethernet
Switch ASICs.
To compile this driver as a module, choose M here: the
module will be called mlxsw_switchx2.
obj-$(CONFIG_MLXSW_CORE) += mlxsw_core.o
mlxsw_core-objs := core.o
obj-$(CONFIG_MLXSW_PCI) += mlxsw_pci.o
mlxsw_pci-objs := pci.o
obj-$(CONFIG_MLXSW_SWITCHX2) += mlxsw_switchx2.o
mlxsw_switchx2-objs := switchx2.o
此差异已折叠。
此差异已折叠。
/*
* drivers/net/ethernet/mellanox/mlxsw/core.h
* Copyright (c) 2015 Mellanox Technologies. All rights reserved.
* Copyright (c) 2015 Jiri Pirko <jiri@mellanox.com>
* Copyright (c) 2015 Ido Schimmel <idosch@mellanox.com>
* Copyright (c) 2015 Elad Raz <eladr@mellanox.com>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. 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.
* 3. Neither the names of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* Alternatively, this software may be distributed under the terms of the
* GNU General Public License ("GPL") version 2 as published by the Free
* Software Foundation.
*
* 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.
*/
#ifndef _MLXSW_CORE_H
#define _MLXSW_CORE_H
#include <linux/module.h>
#include <linux/device.h>
#include <linux/slab.h>
#include <linux/gfp.h>
#include <linux/types.h>
#include <linux/skbuff.h>
#include "trap.h"
#include "reg.h"
#include "cmd.h"
#define MLXSW_MODULE_ALIAS_PREFIX "mlxsw-driver-"
#define MODULE_MLXSW_DRIVER_ALIAS(kind) \
MODULE_ALIAS(MLXSW_MODULE_ALIAS_PREFIX kind)
#define MLXSW_DEVICE_KIND_SWITCHX2 "switchx2"
struct mlxsw_core;
struct mlxsw_driver;
struct mlxsw_bus;
struct mlxsw_bus_info;
int mlxsw_core_driver_register(struct mlxsw_driver *mlxsw_driver);
void mlxsw_core_driver_unregister(struct mlxsw_driver *mlxsw_driver);
int mlxsw_core_bus_device_register(const struct mlxsw_bus_info *mlxsw_bus_info,
const struct mlxsw_bus *mlxsw_bus,
void *bus_priv);
void mlxsw_core_bus_device_unregister(struct mlxsw_core *mlxsw_core);
struct mlxsw_tx_info {
u8 local_port;
bool is_emad;
};
int mlxsw_core_skb_transmit(void *driver_priv, struct sk_buff *skb,
const struct mlxsw_tx_info *tx_info);
struct mlxsw_rx_listener {
void (*func)(struct sk_buff *skb, u8 local_port, void *priv);
u8 local_port;
u16 trap_id;
};
struct mlxsw_event_listener {
void (*func)(const struct mlxsw_reg_info *reg,
char *payload, void *priv);
enum mlxsw_event_trap_id trap_id;
};
int mlxsw_core_rx_listener_register(struct mlxsw_core *mlxsw_core,
const struct mlxsw_rx_listener *rxl,
void *priv);
void mlxsw_core_rx_listener_unregister(struct mlxsw_core *mlxsw_core,
const struct mlxsw_rx_listener *rxl,
void *priv);
int mlxsw_core_event_listener_register(struct mlxsw_core *mlxsw_core,
const struct mlxsw_event_listener *el,
void *priv);
void mlxsw_core_event_listener_unregister(struct mlxsw_core *mlxsw_core,
const struct mlxsw_event_listener *el,
void *priv);
int mlxsw_reg_query(struct mlxsw_core *mlxsw_core,
const struct mlxsw_reg_info *reg, char *payload);
int mlxsw_reg_write(struct mlxsw_core *mlxsw_core,
const struct mlxsw_reg_info *reg, char *payload);
struct mlxsw_rx_info {
u16 sys_port;
int trap_id;
};
void mlxsw_core_skb_receive(struct mlxsw_core *mlxsw_core, struct sk_buff *skb,
struct mlxsw_rx_info *rx_info);
#define MLXSW_CONFIG_PROFILE_SWID_COUNT 8
struct mlxsw_swid_config {
u8 used_type:1,
used_properties:1;
u8 type;
u8 properties;
};
struct mlxsw_config_profile {
u16 used_max_vepa_channels:1,
used_max_lag:1,
used_max_port_per_lag:1,
used_max_mid:1,
used_max_pgt:1,
used_max_system_port:1,
used_max_vlan_groups:1,
used_max_regions:1,
used_flood_tables:1,
used_flood_mode:1,
used_max_ib_mc:1,
used_max_pkey:1,
used_ar_sec:1,
used_adaptive_routing_group_cap:1;
u8 max_vepa_channels;
u16 max_lag;
u16 max_port_per_lag;
u16 max_mid;
u16 max_pgt;
u16 max_system_port;
u16 max_vlan_groups;
u16 max_regions;
u8 max_flood_tables;
u8 max_vid_flood_tables;
u8 flood_mode;
u16 max_ib_mc;
u16 max_pkey;
u8 ar_sec;
u16 adaptive_routing_group_cap;
u8 arn;
struct mlxsw_swid_config swid_config[MLXSW_CONFIG_PROFILE_SWID_COUNT];
};
struct mlxsw_driver {
struct list_head list;
const char *kind;
struct module *owner;
size_t priv_size;
int (*init)(void *driver_priv, struct mlxsw_core *mlxsw_core,
const struct mlxsw_bus_info *mlxsw_bus_info);
void (*fini)(void *driver_priv);
void (*txhdr_construct)(struct sk_buff *skb,
const struct mlxsw_tx_info *tx_info);
u8 txhdr_len;
const struct mlxsw_config_profile *profile;
};
struct mlxsw_bus {
const char *kind;
int (*init)(void *bus_priv, struct mlxsw_core *mlxsw_core,
const struct mlxsw_config_profile *profile);
void (*fini)(void *bus_priv);
int (*skb_transmit)(void *bus_priv, struct sk_buff *skb,
const struct mlxsw_tx_info *tx_info);
int (*cmd_exec)(void *bus_priv, u16 opcode, u8 opcode_mod,
u32 in_mod, bool out_mbox_direct,
char *in_mbox, size_t in_mbox_size,
char *out_mbox, size_t out_mbox_size,
u8 *p_status);
};
struct mlxsw_bus_info {
const char *device_kind;
const char *device_name;
struct device *dev;
struct {
u16 major;
u16 minor;
u16 subminor;
} fw_rev;
u8 vsd[MLXSW_CMD_BOARDINFO_VSD_LEN];
u8 psid[MLXSW_CMD_BOARDINFO_PSID_LEN];
};
#endif
/*
* drivers/net/ethernet/mellanox/mlxsw/emad.h
* Copyright (c) 2015 Mellanox Technologies. All rights reserved.
* Copyright (c) 2015 Ido Schimmel <idosch@mellanox.com>
* Copyright (c) 2015 Jiri Pirko <jiri@mellanox.com>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. 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.
* 3. Neither the names of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* Alternatively, this software may be distributed under the terms of the
* GNU General Public License ("GPL") version 2 as published by the Free
* Software Foundation.
*
* 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.
*/
#ifndef _MLXSW_EMAD_H
#define _MLXSW_EMAD_H
#define MLXSW_EMAD_MAX_FRAME_LEN 1518 /* Length in u8 */
#define MLXSW_EMAD_MAX_RETRY 5
/* EMAD Ethernet header */
#define MLXSW_EMAD_ETH_HDR_LEN 0x10 /* Length in u8 */
#define MLXSW_EMAD_EH_DMAC "\x01\x02\xc9\x00\x00\x01"
#define MLXSW_EMAD_EH_SMAC "\x00\x02\xc9\x01\x02\x03"
#define MLXSW_EMAD_EH_ETHERTYPE 0x8932
#define MLXSW_EMAD_EH_MLX_PROTO 0
#define MLXSW_EMAD_EH_PROTO_VERSION 0
/* EMAD TLV Types */
enum {
MLXSW_EMAD_TLV_TYPE_END,
MLXSW_EMAD_TLV_TYPE_OP,
MLXSW_EMAD_TLV_TYPE_DR,
MLXSW_EMAD_TLV_TYPE_REG,
MLXSW_EMAD_TLV_TYPE_USERDATA,
MLXSW_EMAD_TLV_TYPE_OOBETH,
};
/* OP TLV */
#define MLXSW_EMAD_OP_TLV_LEN 4 /* Length in u32 */
enum {
MLXSW_EMAD_OP_TLV_CLASS_REG_ACCESS = 1,
MLXSW_EMAD_OP_TLV_CLASS_IPC = 2,
};
enum mlxsw_emad_op_tlv_status {
MLXSW_EMAD_OP_TLV_STATUS_SUCCESS,
MLXSW_EMAD_OP_TLV_STATUS_BUSY,
MLXSW_EMAD_OP_TLV_STATUS_VERSION_NOT_SUPPORTED,
MLXSW_EMAD_OP_TLV_STATUS_UNKNOWN_TLV,
MLXSW_EMAD_OP_TLV_STATUS_REGISTER_NOT_SUPPORTED,
MLXSW_EMAD_OP_TLV_STATUS_CLASS_NOT_SUPPORTED,
MLXSW_EMAD_OP_TLV_STATUS_METHOD_NOT_SUPPORTED,
MLXSW_EMAD_OP_TLV_STATUS_BAD_PARAMETER,
MLXSW_EMAD_OP_TLV_STATUS_RESOURCE_NOT_AVAILABLE,
MLXSW_EMAD_OP_TLV_STATUS_MESSAGE_RECEIPT_ACK,
MLXSW_EMAD_OP_TLV_STATUS_INTERNAL_ERROR = 0x70,
};
static inline char *mlxsw_emad_op_tlv_status_str(u8 status)
{
switch (status) {
case MLXSW_EMAD_OP_TLV_STATUS_SUCCESS:
return "operation performed";
case MLXSW_EMAD_OP_TLV_STATUS_BUSY:
return "device is busy";
case MLXSW_EMAD_OP_TLV_STATUS_VERSION_NOT_SUPPORTED:
return "version not supported";
case MLXSW_EMAD_OP_TLV_STATUS_UNKNOWN_TLV:
return "unknown TLV";
case MLXSW_EMAD_OP_TLV_STATUS_REGISTER_NOT_SUPPORTED:
return "register not supported";
case MLXSW_EMAD_OP_TLV_STATUS_CLASS_NOT_SUPPORTED:
return "class not supported";
case MLXSW_EMAD_OP_TLV_STATUS_METHOD_NOT_SUPPORTED:
return "method not supported";
case MLXSW_EMAD_OP_TLV_STATUS_BAD_PARAMETER:
return "bad parameter";
case MLXSW_EMAD_OP_TLV_STATUS_RESOURCE_NOT_AVAILABLE:
return "resource not available";
case MLXSW_EMAD_OP_TLV_STATUS_MESSAGE_RECEIPT_ACK:
return "acknowledged. retransmit";
case MLXSW_EMAD_OP_TLV_STATUS_INTERNAL_ERROR:
return "internal error";
default:
return "*UNKNOWN*";
}
}
enum {
MLXSW_EMAD_OP_TLV_REQUEST,
MLXSW_EMAD_OP_TLV_RESPONSE
};
enum {
MLXSW_EMAD_OP_TLV_METHOD_QUERY = 1,
MLXSW_EMAD_OP_TLV_METHOD_WRITE = 2,
MLXSW_EMAD_OP_TLV_METHOD_SEND = 3,
MLXSW_EMAD_OP_TLV_METHOD_EVENT = 5,
};
/* END TLV */
#define MLXSW_EMAD_END_TLV_LEN 1 /* Length in u32 */
#endif
/*
* drivers/net/ethernet/mellanox/mlxsw/item.h
* Copyright (c) 2015 Mellanox Technologies. All rights reserved.
* Copyright (c) 2015 Jiri Pirko <jiri@mellanox.com>
* Copyright (c) 2015 Ido Schimmel <idosch@mellanox.com>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. 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.
* 3. Neither the names of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* Alternatively, this software may be distributed under the terms of the
* GNU General Public License ("GPL") version 2 as published by the Free
* Software Foundation.
*
* 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.
*/
#ifndef _MLXSW_ITEM_H
#define _MLXSW_ITEM_H
#include <linux/types.h>
#include <linux/string.h>
#include <linux/bitops.h>
struct mlxsw_item {
unsigned short offset; /* bytes in container */
unsigned short step; /* step in bytes for indexed items */
unsigned short in_step_offset; /* offset within one step */
unsigned char shift; /* shift in bits */
unsigned char element_size; /* size of element in bit array */
bool no_real_shift;
union {
unsigned char bits;
unsigned short bytes;
} size;
const char *name;
};
static inline unsigned int
__mlxsw_item_offset(struct mlxsw_item *item, unsigned short index,
size_t typesize)
{
BUG_ON(index && !item->step);
if (item->offset % typesize != 0 ||
item->step % typesize != 0 ||
item->in_step_offset % typesize != 0) {
pr_err("mlxsw: item bug (name=%s,offset=%x,step=%x,in_step_offset=%x,typesize=%lx)\n",
item->name, item->offset, item->step,
item->in_step_offset, typesize);
BUG();
}
return ((item->offset + item->step * index + item->in_step_offset) /
typesize);
}
static inline u16 __mlxsw_item_get16(char *buf, struct mlxsw_item *item,
unsigned short index)
{
unsigned int offset = __mlxsw_item_offset(item, index, sizeof(u16));
__be16 *b = (__be16 *) buf;
u16 tmp;
tmp = be16_to_cpu(b[offset]);
tmp >>= item->shift;
tmp &= GENMASK(item->size.bits - 1, 0);
if (item->no_real_shift)
tmp <<= item->shift;
return tmp;
}
static inline void __mlxsw_item_set16(char *buf, struct mlxsw_item *item,
unsigned short index, u16 val)
{
unsigned int offset = __mlxsw_item_offset(item, index,
sizeof(u16));
__be16 *b = (__be16 *) buf;
u16 mask = GENMASK(item->size.bits - 1, 0) << item->shift;
u16 tmp;
if (!item->no_real_shift)
val <<= item->shift;
val &= mask;
tmp = be16_to_cpu(b[offset]);
tmp &= ~mask;
tmp |= val;
b[offset] = cpu_to_be16(tmp);
}
static inline u32 __mlxsw_item_get32(char *buf, struct mlxsw_item *item,
unsigned short index)
{
unsigned int offset = __mlxsw_item_offset(item, index, sizeof(u32));
__be32 *b = (__be32 *) buf;
u32 tmp;
tmp = be32_to_cpu(b[offset]);
tmp >>= item->shift;
tmp &= GENMASK(item->size.bits - 1, 0);
if (item->no_real_shift)
tmp <<= item->shift;
return tmp;
}
static inline void __mlxsw_item_set32(char *buf, struct mlxsw_item *item,
unsigned short index, u32 val)
{
unsigned int offset = __mlxsw_item_offset(item, index,
sizeof(u32));
__be32 *b = (__be32 *) buf;
u32 mask = GENMASK(item->size.bits - 1, 0) << item->shift;
u32 tmp;
if (!item->no_real_shift)
val <<= item->shift;
val &= mask;
tmp = be32_to_cpu(b[offset]);
tmp &= ~mask;
tmp |= val;
b[offset] = cpu_to_be32(tmp);
}
static inline u64 __mlxsw_item_get64(char *buf, struct mlxsw_item *item,
unsigned short index)
{
unsigned int offset = __mlxsw_item_offset(item, index, sizeof(u64));
__be64 *b = (__be64 *) buf;
u64 tmp;
tmp = be64_to_cpu(b[offset]);
tmp >>= item->shift;
tmp &= GENMASK_ULL(item->size.bits - 1, 0);
if (item->no_real_shift)
tmp <<= item->shift;
return tmp;
}
static inline void __mlxsw_item_set64(char *buf, struct mlxsw_item *item,
unsigned short index, u64 val)
{
unsigned int offset = __mlxsw_item_offset(item, index, sizeof(u64));
__be64 *b = (__be64 *) buf;
u64 mask = GENMASK_ULL(item->size.bits - 1, 0) << item->shift;
u64 tmp;
if (!item->no_real_shift)
val <<= item->shift;
val &= mask;
tmp = be64_to_cpu(b[offset]);
tmp &= ~mask;
tmp |= val;
b[offset] = cpu_to_be64(tmp);
}
static inline void __mlxsw_item_memcpy_from(char *buf, char *dst,
struct mlxsw_item *item)
{
memcpy(dst, &buf[item->offset], item->size.bytes);
}
static inline void __mlxsw_item_memcpy_to(char *buf, char *src,
struct mlxsw_item *item)
{
memcpy(&buf[item->offset], src, item->size.bytes);
}
static inline u16
__mlxsw_item_bit_array_offset(struct mlxsw_item *item, u16 index, u8 *shift)
{
u16 max_index, be_index;
u16 offset; /* byte offset inside the array */
BUG_ON(index && !item->element_size);
if (item->offset % sizeof(u32) != 0 ||
BITS_PER_BYTE % item->element_size != 0) {
pr_err("mlxsw: item bug (name=%s,offset=%x,element_size=%x)\n",
item->name, item->offset, item->element_size);
BUG();
}
max_index = (item->size.bytes << 3) / item->element_size - 1;
be_index = max_index - index;
offset = be_index * item->element_size >> 3;
*shift = index % (BITS_PER_BYTE / item->element_size) << 1;
return item->offset + offset;
}
static inline u8 __mlxsw_item_bit_array_get(char *buf, struct mlxsw_item *item,
u16 index)
{
u8 shift, tmp;
u16 offset = __mlxsw_item_bit_array_offset(item, index, &shift);
tmp = buf[offset];
tmp >>= shift;
tmp &= GENMASK(item->element_size - 1, 0);
return tmp;
}
static inline void __mlxsw_item_bit_array_set(char *buf, struct mlxsw_item *item,
u16 index, u8 val)
{
u8 shift, tmp;
u16 offset = __mlxsw_item_bit_array_offset(item, index, &shift);
u8 mask = GENMASK(item->element_size - 1, 0) << shift;
val <<= shift;
val &= mask;
tmp = buf[offset];
tmp &= ~mask;
tmp |= val;
buf[offset] = tmp;
}
#define __ITEM_NAME(_type, _cname, _iname) \
mlxsw_##_type##_##_cname##_##_iname##_item
/* _type: cmd_mbox, reg, etc.
* _cname: containter name (e.g. command name, register name)
* _iname: item name within the container
*/
#define MLXSW_ITEM16(_type, _cname, _iname, _offset, _shift, _sizebits) \
static struct mlxsw_item __ITEM_NAME(_type, _cname, _iname) = { \
.offset = _offset, \
.shift = _shift, \
.size = {.bits = _sizebits,}, \
.name = #_type "_" #_cname "_" #_iname, \
}; \
static inline u16 mlxsw_##_type##_##_cname##_##_iname##_get(char *buf) \
{ \
return __mlxsw_item_get16(buf, &__ITEM_NAME(_type, _cname, _iname), 0); \
} \
static inline void mlxsw_##_type##_##_cname##_##_iname##_set(char *buf, u16 val)\
{ \
__mlxsw_item_set16(buf, &__ITEM_NAME(_type, _cname, _iname), 0, val); \
}
#define MLXSW_ITEM16_INDEXED(_type, _cname, _iname, _offset, _shift, _sizebits, \
_step, _instepoffset, _norealshift) \
static struct mlxsw_item __ITEM_NAME(_type, _cname, _iname) = { \
.offset = _offset, \
.step = _step, \
.in_step_offset = _instepoffset, \
.shift = _shift, \
.no_real_shift = _norealshift, \
.size = {.bits = _sizebits,}, \
.name = #_type "_" #_cname "_" #_iname, \
}; \
static inline u16 \
mlxsw_##_type##_##_cname##_##_iname##_get(char *buf, unsigned short index) \
{ \
return __mlxsw_item_get16(buf, &__ITEM_NAME(_type, _cname, _iname), \
index); \
} \
static inline void \
mlxsw_##_type##_##_cname##_##_iname##_set(char *buf, unsigned short index, \
u16 val) \
{ \
__mlxsw_item_set16(buf, &__ITEM_NAME(_type, _cname, _iname), \
index, val); \
}
#define MLXSW_ITEM32(_type, _cname, _iname, _offset, _shift, _sizebits) \
static struct mlxsw_item __ITEM_NAME(_type, _cname, _iname) = { \
.offset = _offset, \
.shift = _shift, \
.size = {.bits = _sizebits,}, \
.name = #_type "_" #_cname "_" #_iname, \
}; \
static inline u32 mlxsw_##_type##_##_cname##_##_iname##_get(char *buf) \
{ \
return __mlxsw_item_get32(buf, &__ITEM_NAME(_type, _cname, _iname), 0); \
} \
static inline void mlxsw_##_type##_##_cname##_##_iname##_set(char *buf, u32 val)\
{ \
__mlxsw_item_set32(buf, &__ITEM_NAME(_type, _cname, _iname), 0, val); \
}
#define MLXSW_ITEM32_INDEXED(_type, _cname, _iname, _offset, _shift, _sizebits, \
_step, _instepoffset, _norealshift) \
static struct mlxsw_item __ITEM_NAME(_type, _cname, _iname) = { \
.offset = _offset, \
.step = _step, \
.in_step_offset = _instepoffset, \
.shift = _shift, \
.no_real_shift = _norealshift, \
.size = {.bits = _sizebits,}, \
.name = #_type "_" #_cname "_" #_iname, \
}; \
static inline u32 \
mlxsw_##_type##_##_cname##_##_iname##_get(char *buf, unsigned short index) \
{ \
return __mlxsw_item_get32(buf, &__ITEM_NAME(_type, _cname, _iname), \
index); \
} \
static inline void \
mlxsw_##_type##_##_cname##_##_iname##_set(char *buf, unsigned short index, \
u32 val) \
{ \
__mlxsw_item_set32(buf, &__ITEM_NAME(_type, _cname, _iname), \
index, val); \
}
#define MLXSW_ITEM64(_type, _cname, _iname, _offset, _shift, _sizebits) \
static struct mlxsw_item __ITEM_NAME(_type, _cname, _iname) = { \
.offset = _offset, \
.shift = _shift, \
.size = {.bits = _sizebits,}, \
.name = #_type "_" #_cname "_" #_iname, \
}; \
static inline u64 mlxsw_##_type##_##_cname##_##_iname##_get(char *buf) \
{ \
return __mlxsw_item_get64(buf, &__ITEM_NAME(_type, _cname, _iname), 0); \
} \
static inline void mlxsw_##_type##_##_cname##_##_iname##_set(char *buf, u64 val)\
{ \
__mlxsw_item_set64(buf, &__ITEM_NAME(_type, _cname, _iname), 0, val); \
}
#define MLXSW_ITEM64_INDEXED(_type, _cname, _iname, _offset, _shift, \
_sizebits, _step, _instepoffset, _norealshift) \
static struct mlxsw_item __ITEM_NAME(_type, _cname, _iname) = { \
.offset = _offset, \
.step = _step, \
.in_step_offset = _instepoffset, \
.shift = _shift, \
.no_real_shift = _norealshift, \
.size = {.bits = _sizebits,}, \
.name = #_type "_" #_cname "_" #_iname, \
}; \
static inline u64 \
mlxsw_##_type##_##_cname##_##_iname##_get(char *buf, unsigned short index) \
{ \
return __mlxsw_item_get64(buf, &__ITEM_NAME(_type, _cname, _iname), \
index); \
} \
static inline void \
mlxsw_##_type##_##_cname##_##_iname##_set(char *buf, unsigned short index, \
u64 val) \
{ \
__mlxsw_item_set64(buf, &__ITEM_NAME(_type, _cname, _iname), \
index, val); \
}
#define MLXSW_ITEM_BUF(_type, _cname, _iname, _offset, _sizebytes) \
static struct mlxsw_item __ITEM_NAME(_type, _cname, _iname) = { \
.offset = _offset, \
.size = {.bytes = _sizebytes,}, \
.name = #_type "_" #_cname "_" #_iname, \
}; \
static inline void \
mlxsw_##_type##_##_cname##_##_iname##_memcpy_from(char *buf, char *dst) \
{ \
__mlxsw_item_memcpy_from(buf, dst, &__ITEM_NAME(_type, _cname, _iname));\
} \
static inline void \
mlxsw_##_type##_##_cname##_##_iname##_memcpy_to(char *buf, char *src) \
{ \
__mlxsw_item_memcpy_to(buf, src, &__ITEM_NAME(_type, _cname, _iname)); \
}
#define MLXSW_ITEM_BIT_ARRAY(_type, _cname, _iname, _offset, _sizebytes, \
_element_size) \
static struct mlxsw_item __ITEM_NAME(_type, _cname, _iname) = { \
.offset = _offset, \
.element_size = _element_size, \
.size = {.bytes = _sizebytes,}, \
.name = #_type "_" #_cname "_" #_iname, \
}; \
static inline u8 \
mlxsw_##_type##_##_cname##_##_iname##_get(char *buf, u16 index) \
{ \
return __mlxsw_item_bit_array_get(buf, \
&__ITEM_NAME(_type, _cname, _iname), \
index); \
} \
static inline void \
mlxsw_##_type##_##_cname##_##_iname##_set(char *buf, u16 index, u8 val) \
{ \
return __mlxsw_item_bit_array_set(buf, \
&__ITEM_NAME(_type, _cname, _iname), \
index, val); \
} \
#endif
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册