提交 db14dff1 编写于 作者: D Doug Ledford

Merge tag 'rdma-next-2017-08-10' of...

Merge tag 'rdma-next-2017-08-10' of git://git.kernel.org/pub/scm/linux/kernel/git/leon/linux-rdma into rdma-netlink

RDMA netlink infrastructure v2
Signed-off-by: NDoug Ledford <dledford@redhat.com>
...@@ -11,7 +11,8 @@ ib_core-y := packer.o ud_header.o verbs.o cq.o rw.o sysfs.o \ ...@@ -11,7 +11,8 @@ ib_core-y := packer.o ud_header.o verbs.o cq.o rw.o sysfs.o \
device.o fmr_pool.o cache.o netlink.o \ device.o fmr_pool.o cache.o netlink.o \
roce_gid_mgmt.o mr_pool.o addr.o sa_query.o \ roce_gid_mgmt.o mr_pool.o addr.o sa_query.o \
multicast.o mad.o smi.o agent.o mad_rmpp.o \ multicast.o mad.o smi.o agent.o mad_rmpp.o \
security.o security.o nldev.o
ib_core-$(CONFIG_INFINIBAND_USER_MEM) += umem.o ib_core-$(CONFIG_INFINIBAND_USER_MEM) += umem.o
ib_core-$(CONFIG_INFINIBAND_ON_DEMAND_PAGING) += umem_odp.o umem_rbtree.o ib_core-$(CONFIG_INFINIBAND_ON_DEMAND_PAGING) += umem_odp.o umem_rbtree.o
ib_core-$(CONFIG_CGROUP_RDMA) += cgroup.o ib_core-$(CONFIG_CGROUP_RDMA) += cgroup.o
......
...@@ -129,13 +129,11 @@ static void ib_nl_process_good_ip_rsep(const struct nlmsghdr *nlh) ...@@ -129,13 +129,11 @@ static void ib_nl_process_good_ip_rsep(const struct nlmsghdr *nlh)
} }
int ib_nl_handle_ip_res_resp(struct sk_buff *skb, int ib_nl_handle_ip_res_resp(struct sk_buff *skb,
struct netlink_callback *cb) struct nlmsghdr *nlh,
struct netlink_ext_ack *extack)
{ {
const struct nlmsghdr *nlh = (struct nlmsghdr *)cb->nlh;
if ((nlh->nlmsg_flags & NLM_F_REQUEST) || if ((nlh->nlmsg_flags & NLM_F_REQUEST) ||
!(NETLINK_CB(skb).sk) || !(NETLINK_CB(skb).sk))
!netlink_capable(skb, CAP_NET_ADMIN))
return -EPERM; return -EPERM;
if (ib_nl_is_good_ip_resp(nlh)) if (ib_nl_is_good_ip_resp(nlh))
...@@ -185,7 +183,7 @@ static int ib_nl_ip_send_msg(struct rdma_dev_addr *dev_addr, ...@@ -185,7 +183,7 @@ static int ib_nl_ip_send_msg(struct rdma_dev_addr *dev_addr,
/* Repair the nlmsg header length */ /* Repair the nlmsg header length */
nlmsg_end(skb, nlh); nlmsg_end(skb, nlh);
ibnl_multicast(skb, nlh, RDMA_NL_GROUP_LS, GFP_KERNEL); rdma_nl_multicast(skb, RDMA_NL_GROUP_LS, GFP_KERNEL);
/* Make the request retry, so when we get the response from userspace /* Make the request retry, so when we get the response from userspace
* we will have something. * we will have something.
...@@ -326,7 +324,7 @@ static void queue_req(struct addr_req *req) ...@@ -326,7 +324,7 @@ static void queue_req(struct addr_req *req)
static int ib_nl_fetch_ha(struct dst_entry *dst, struct rdma_dev_addr *dev_addr, static int ib_nl_fetch_ha(struct dst_entry *dst, struct rdma_dev_addr *dev_addr,
const void *daddr, u32 seq, u16 family) const void *daddr, u32 seq, u16 family)
{ {
if (ibnl_chk_listeners(RDMA_NL_GROUP_LS)) if (rdma_nl_chk_listeners(RDMA_NL_GROUP_LS))
return -EADDRNOTAVAIL; return -EADDRNOTAVAIL;
/* We fill in what we can, the response will fill the rest */ /* We fill in what we can, the response will fill the rest */
......
...@@ -72,6 +72,7 @@ MODULE_LICENSE("Dual BSD/GPL"); ...@@ -72,6 +72,7 @@ MODULE_LICENSE("Dual BSD/GPL");
#define CMA_MAX_CM_RETRIES 15 #define CMA_MAX_CM_RETRIES 15
#define CMA_CM_MRA_SETTING (IB_CM_MRA_FLAG_DELAY | 24) #define CMA_CM_MRA_SETTING (IB_CM_MRA_FLAG_DELAY | 24)
#define CMA_IBOE_PACKET_LIFETIME 18 #define CMA_IBOE_PACKET_LIFETIME 18
#define CMA_PREFERRED_ROCE_GID_TYPE (1 << IB_GID_TYPE_ROCE_UDP_ENCAP)
static const char * const cma_events[] = { static const char * const cma_events[] = {
[RDMA_CM_EVENT_ADDR_RESOLVED] = "address resolved", [RDMA_CM_EVENT_ADDR_RESOLVED] = "address resolved",
...@@ -3998,7 +3999,8 @@ static void iboe_mcast_work_handler(struct work_struct *work) ...@@ -3998,7 +3999,8 @@ static void iboe_mcast_work_handler(struct work_struct *work)
kfree(mw); kfree(mw);
} }
static void cma_iboe_set_mgid(struct sockaddr *addr, union ib_gid *mgid) static void cma_iboe_set_mgid(struct sockaddr *addr, union ib_gid *mgid,
enum ib_gid_type gid_type)
{ {
struct sockaddr_in *sin = (struct sockaddr_in *)addr; struct sockaddr_in *sin = (struct sockaddr_in *)addr;
struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)addr; struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)addr;
...@@ -4008,8 +4010,8 @@ static void cma_iboe_set_mgid(struct sockaddr *addr, union ib_gid *mgid) ...@@ -4008,8 +4010,8 @@ static void cma_iboe_set_mgid(struct sockaddr *addr, union ib_gid *mgid)
} else if (addr->sa_family == AF_INET6) { } else if (addr->sa_family == AF_INET6) {
memcpy(mgid, &sin6->sin6_addr, sizeof *mgid); memcpy(mgid, &sin6->sin6_addr, sizeof *mgid);
} else { } else {
mgid->raw[0] = 0xff; mgid->raw[0] = (gid_type == IB_GID_TYPE_IB) ? 0xff : 0;
mgid->raw[1] = 0x0e; mgid->raw[1] = (gid_type == IB_GID_TYPE_IB) ? 0x0e : 0;
mgid->raw[2] = 0; mgid->raw[2] = 0;
mgid->raw[3] = 0; mgid->raw[3] = 0;
mgid->raw[4] = 0; mgid->raw[4] = 0;
...@@ -4050,7 +4052,9 @@ static int cma_iboe_join_multicast(struct rdma_id_private *id_priv, ...@@ -4050,7 +4052,9 @@ static int cma_iboe_join_multicast(struct rdma_id_private *id_priv,
goto out1; goto out1;
} }
cma_iboe_set_mgid(addr, &mc->multicast.ib->rec.mgid); gid_type = id_priv->cma_dev->default_gid_type[id_priv->id.port_num -
rdma_start_port(id_priv->cma_dev->device)];
cma_iboe_set_mgid(addr, &mc->multicast.ib->rec.mgid, gid_type);
mc->multicast.ib->rec.pkey = cpu_to_be16(0xffff); mc->multicast.ib->rec.pkey = cpu_to_be16(0xffff);
if (id_priv->id.ps == RDMA_PS_UDP) if (id_priv->id.ps == RDMA_PS_UDP)
...@@ -4066,8 +4070,6 @@ static int cma_iboe_join_multicast(struct rdma_id_private *id_priv, ...@@ -4066,8 +4070,6 @@ static int cma_iboe_join_multicast(struct rdma_id_private *id_priv,
mc->multicast.ib->rec.hop_limit = 1; mc->multicast.ib->rec.hop_limit = 1;
mc->multicast.ib->rec.mtu = iboe_get_mtu(ndev->mtu); mc->multicast.ib->rec.mtu = iboe_get_mtu(ndev->mtu);
gid_type = id_priv->cma_dev->default_gid_type[id_priv->id.port_num -
rdma_start_port(id_priv->cma_dev->device)];
if (addr->sa_family == AF_INET) { if (addr->sa_family == AF_INET) {
if (gid_type == IB_GID_TYPE_ROCE_UDP_ENCAP) { if (gid_type == IB_GID_TYPE_ROCE_UDP_ENCAP) {
mc->multicast.ib->rec.hop_limit = IPV6_DEFAULT_HOPLIMIT; mc->multicast.ib->rec.hop_limit = IPV6_DEFAULT_HOPLIMIT;
...@@ -4280,8 +4282,12 @@ static void cma_add_one(struct ib_device *device) ...@@ -4280,8 +4282,12 @@ static void cma_add_one(struct ib_device *device)
for (i = rdma_start_port(device); i <= rdma_end_port(device); i++) { for (i = rdma_start_port(device); i <= rdma_end_port(device); i++) {
supported_gids = roce_gid_type_mask_support(device, i); supported_gids = roce_gid_type_mask_support(device, i);
WARN_ON(!supported_gids); WARN_ON(!supported_gids);
cma_dev->default_gid_type[i - rdma_start_port(device)] = if (supported_gids & CMA_PREFERRED_ROCE_GID_TYPE)
find_first_bit(&supported_gids, BITS_PER_LONG); cma_dev->default_gid_type[i - rdma_start_port(device)] =
CMA_PREFERRED_ROCE_GID_TYPE;
else
cma_dev->default_gid_type[i - rdma_start_port(device)] =
find_first_bit(&supported_gids, BITS_PER_LONG);
cma_dev->default_roce_tos[i - rdma_start_port(device)] = 0; cma_dev->default_roce_tos[i - rdma_start_port(device)] = 0;
} }
...@@ -4452,9 +4458,8 @@ static int cma_get_id_stats(struct sk_buff *skb, struct netlink_callback *cb) ...@@ -4452,9 +4458,8 @@ static int cma_get_id_stats(struct sk_buff *skb, struct netlink_callback *cb)
return skb->len; return skb->len;
} }
static const struct ibnl_client_cbs cma_cb_table[] = { static const struct rdma_nl_cbs cma_cb_table[] = {
[RDMA_NL_RDMA_CM_ID_STATS] = { .dump = cma_get_id_stats, [RDMA_NL_RDMA_CM_ID_STATS] = { .dump = cma_get_id_stats},
.module = THIS_MODULE },
}; };
static int cma_init_net(struct net *net) static int cma_init_net(struct net *net)
...@@ -4506,9 +4511,7 @@ static int __init cma_init(void) ...@@ -4506,9 +4511,7 @@ static int __init cma_init(void)
if (ret) if (ret)
goto err; goto err;
if (ibnl_add_client(RDMA_NL_RDMA_CM, ARRAY_SIZE(cma_cb_table), rdma_nl_register(RDMA_NL_RDMA_CM, cma_cb_table);
cma_cb_table))
pr_warn("RDMA CMA: failed to add netlink callback\n");
cma_configfs_init(); cma_configfs_init();
return 0; return 0;
...@@ -4525,7 +4528,7 @@ static int __init cma_init(void) ...@@ -4525,7 +4528,7 @@ static int __init cma_init(void)
static void __exit cma_cleanup(void) static void __exit cma_cleanup(void)
{ {
cma_configfs_exit(); cma_configfs_exit();
ibnl_remove_client(RDMA_NL_RDMA_CM); rdma_nl_unregister(RDMA_NL_RDMA_CM);
ib_unregister_client(&cma_client); ib_unregister_client(&cma_client);
unregister_netdevice_notifier(&cma_nb); unregister_netdevice_notifier(&cma_nb);
rdma_addr_unregister_client(&addr_client); rdma_addr_unregister_client(&addr_client);
......
...@@ -102,6 +102,14 @@ void ib_enum_all_roce_netdevs(roce_netdev_filter filter, ...@@ -102,6 +102,14 @@ void ib_enum_all_roce_netdevs(roce_netdev_filter filter,
roce_netdev_callback cb, roce_netdev_callback cb,
void *cookie); void *cookie);
typedef int (*nldev_callback)(struct ib_device *device,
struct sk_buff *skb,
struct netlink_callback *cb,
unsigned int idx);
int ib_enum_all_devs(nldev_callback nldev_cb, struct sk_buff *skb,
struct netlink_callback *cb);
enum ib_cache_gid_default_mode { enum ib_cache_gid_default_mode {
IB_CACHE_GID_DEFAULT_MODE_SET, IB_CACHE_GID_DEFAULT_MODE_SET,
IB_CACHE_GID_DEFAULT_MODE_DELETE IB_CACHE_GID_DEFAULT_MODE_DELETE
...@@ -179,8 +187,8 @@ void ib_mad_cleanup(void); ...@@ -179,8 +187,8 @@ void ib_mad_cleanup(void);
int ib_sa_init(void); int ib_sa_init(void);
void ib_sa_cleanup(void); void ib_sa_cleanup(void);
int ibnl_init(void); int rdma_nl_init(void);
void ibnl_cleanup(void); void rdma_nl_exit(void);
/** /**
* Check if there are any listeners to the netlink group * Check if there are any listeners to the netlink group
...@@ -190,11 +198,14 @@ void ibnl_cleanup(void); ...@@ -190,11 +198,14 @@ void ibnl_cleanup(void);
int ibnl_chk_listeners(unsigned int group); int ibnl_chk_listeners(unsigned int group);
int ib_nl_handle_resolve_resp(struct sk_buff *skb, int ib_nl_handle_resolve_resp(struct sk_buff *skb,
struct netlink_callback *cb); struct nlmsghdr *nlh,
struct netlink_ext_ack *extack);
int ib_nl_handle_set_timeout(struct sk_buff *skb, int ib_nl_handle_set_timeout(struct sk_buff *skb,
struct netlink_callback *cb); struct nlmsghdr *nlh,
struct netlink_ext_ack *extack);
int ib_nl_handle_ip_res_resp(struct sk_buff *skb, int ib_nl_handle_ip_res_resp(struct sk_buff *skb,
struct netlink_callback *cb); struct nlmsghdr *nlh,
struct netlink_ext_ack *extack);
int ib_get_cached_subnet_prefix(struct ib_device *device, int ib_get_cached_subnet_prefix(struct ib_device *device,
u8 port_num, u8 port_num,
...@@ -301,4 +312,9 @@ static inline int ib_mad_enforce_security(struct ib_mad_agent_private *map, ...@@ -301,4 +312,9 @@ static inline int ib_mad_enforce_security(struct ib_mad_agent_private *map,
return 0; return 0;
} }
#endif #endif
struct ib_device *__ib_device_get_by_index(u32 ifindex);
/* RDMA device netlink */
void nldev_init(void);
void nldev_exit(void);
#endif /* _CORE_PRIV_H */ #endif /* _CORE_PRIV_H */
...@@ -134,6 +134,17 @@ static int ib_device_check_mandatory(struct ib_device *device) ...@@ -134,6 +134,17 @@ static int ib_device_check_mandatory(struct ib_device *device)
return 0; return 0;
} }
struct ib_device *__ib_device_get_by_index(u32 index)
{
struct ib_device *device;
list_for_each_entry(device, &device_list, core_list)
if (device->index == index)
return device;
return NULL;
}
static struct ib_device *__ib_device_get_by_name(const char *name) static struct ib_device *__ib_device_get_by_name(const char *name)
{ {
struct ib_device *device; struct ib_device *device;
...@@ -145,7 +156,6 @@ static struct ib_device *__ib_device_get_by_name(const char *name) ...@@ -145,7 +156,6 @@ static struct ib_device *__ib_device_get_by_name(const char *name)
return NULL; return NULL;
} }
static int alloc_name(char *name) static int alloc_name(char *name)
{ {
unsigned long *inuse; unsigned long *inuse;
...@@ -326,10 +336,10 @@ static int read_port_immutable(struct ib_device *device) ...@@ -326,10 +336,10 @@ static int read_port_immutable(struct ib_device *device)
return 0; return 0;
} }
void ib_get_device_fw_str(struct ib_device *dev, char *str, size_t str_len) void ib_get_device_fw_str(struct ib_device *dev, char *str)
{ {
if (dev->get_dev_fw_str) if (dev->get_dev_fw_str)
dev->get_dev_fw_str(dev, str, str_len); dev->get_dev_fw_str(dev, str);
else else
str[0] = '\0'; str[0] = '\0';
} }
...@@ -394,6 +404,30 @@ static int ib_security_change(struct notifier_block *nb, unsigned long event, ...@@ -394,6 +404,30 @@ static int ib_security_change(struct notifier_block *nb, unsigned long event,
return NOTIFY_OK; return NOTIFY_OK;
} }
/**
* __dev_new_index - allocate an device index
*
* Returns a suitable unique value for a new device interface
* number. It assumes that there are less than 2^32-1 ib devices
* will be present in the system.
*/
static u32 __dev_new_index(void)
{
/*
* The device index to allow stable naming.
* Similar to struct net -> ifindex.
*/
static u32 index;
for (;;) {
if (!(++index))
index = 1;
if (!__ib_device_get_by_index(index))
return index;
}
}
/** /**
* ib_register_device - Register an IB device with IB core * ib_register_device - Register an IB device with IB core
* @device:Device to register * @device:Device to register
...@@ -492,6 +526,7 @@ int ib_register_device(struct ib_device *device, ...@@ -492,6 +526,7 @@ int ib_register_device(struct ib_device *device,
if (client->add && !add_client_context(device, client)) if (client->add && !add_client_context(device, client))
client->add(device); client->add(device);
device->index = __dev_new_index();
down_write(&lists_rwsem); down_write(&lists_rwsem);
list_add_tail(&device->core_list, &device_list); list_add_tail(&device->core_list, &device_list);
up_write(&lists_rwsem); up_write(&lists_rwsem);
...@@ -892,6 +927,31 @@ void ib_enum_all_roce_netdevs(roce_netdev_filter filter, ...@@ -892,6 +927,31 @@ void ib_enum_all_roce_netdevs(roce_netdev_filter filter,
up_read(&lists_rwsem); up_read(&lists_rwsem);
} }
/**
* ib_enum_all_devs - enumerate all ib_devices
* @cb: Callback to call for each found ib_device
*
* Enumerates all ib_devices and calls callback() on each device.
*/
int ib_enum_all_devs(nldev_callback nldev_cb, struct sk_buff *skb,
struct netlink_callback *cb)
{
struct ib_device *dev;
unsigned int idx = 0;
int ret = 0;
down_read(&lists_rwsem);
list_for_each_entry(dev, &device_list, core_list) {
ret = nldev_cb(dev, skb, cb, idx);
if (ret)
break;
idx++;
}
up_read(&lists_rwsem);
return ret;
}
/** /**
* ib_query_pkey - Get P_Key table entry * ib_query_pkey - Get P_Key table entry
* @device:Device to query * @device:Device to query
...@@ -1086,29 +1146,21 @@ struct net_device *ib_get_net_dev_by_params(struct ib_device *dev, ...@@ -1086,29 +1146,21 @@ struct net_device *ib_get_net_dev_by_params(struct ib_device *dev,
} }
EXPORT_SYMBOL(ib_get_net_dev_by_params); EXPORT_SYMBOL(ib_get_net_dev_by_params);
static struct ibnl_client_cbs ibnl_ls_cb_table[] = { static const struct rdma_nl_cbs ibnl_ls_cb_table[] = {
[RDMA_NL_LS_OP_RESOLVE] = { [RDMA_NL_LS_OP_RESOLVE] = {
.dump = ib_nl_handle_resolve_resp, .doit = ib_nl_handle_resolve_resp,
.module = THIS_MODULE }, .flags = RDMA_NL_ADMIN_PERM,
},
[RDMA_NL_LS_OP_SET_TIMEOUT] = { [RDMA_NL_LS_OP_SET_TIMEOUT] = {
.dump = ib_nl_handle_set_timeout, .doit = ib_nl_handle_set_timeout,
.module = THIS_MODULE }, .flags = RDMA_NL_ADMIN_PERM,
},
[RDMA_NL_LS_OP_IP_RESOLVE] = { [RDMA_NL_LS_OP_IP_RESOLVE] = {
.dump = ib_nl_handle_ip_res_resp, .doit = ib_nl_handle_ip_res_resp,
.module = THIS_MODULE }, .flags = RDMA_NL_ADMIN_PERM,
},
}; };
static int ib_add_ibnl_clients(void)
{
return ibnl_add_client(RDMA_NL_LS, ARRAY_SIZE(ibnl_ls_cb_table),
ibnl_ls_cb_table);
}
static void ib_remove_ibnl_clients(void)
{
ibnl_remove_client(RDMA_NL_LS);
}
static int __init ib_core_init(void) static int __init ib_core_init(void)
{ {
int ret; int ret;
...@@ -1130,9 +1182,9 @@ static int __init ib_core_init(void) ...@@ -1130,9 +1182,9 @@ static int __init ib_core_init(void)
goto err_comp; goto err_comp;
} }
ret = ibnl_init(); ret = rdma_nl_init();
if (ret) { if (ret) {
pr_warn("Couldn't init IB netlink interface\n"); pr_warn("Couldn't init IB netlink interface: err %d\n", ret);
goto err_sysfs; goto err_sysfs;
} }
...@@ -1154,24 +1206,18 @@ static int __init ib_core_init(void) ...@@ -1154,24 +1206,18 @@ static int __init ib_core_init(void)
goto err_mad; goto err_mad;
} }
ret = ib_add_ibnl_clients();
if (ret) {
pr_warn("Couldn't register ibnl clients\n");
goto err_sa;
}
ret = register_lsm_notifier(&ibdev_lsm_nb); ret = register_lsm_notifier(&ibdev_lsm_nb);
if (ret) { if (ret) {
pr_warn("Couldn't register LSM notifier. ret %d\n", ret); pr_warn("Couldn't register LSM notifier. ret %d\n", ret);
goto err_ibnl_clients; goto err_sa;
} }
nldev_init();
rdma_nl_register(RDMA_NL_LS, ibnl_ls_cb_table);
ib_cache_setup(); ib_cache_setup();
return 0; return 0;
err_ibnl_clients:
ib_remove_ibnl_clients();
err_sa: err_sa:
ib_sa_cleanup(); ib_sa_cleanup();
err_mad: err_mad:
...@@ -1179,7 +1225,7 @@ static int __init ib_core_init(void) ...@@ -1179,7 +1225,7 @@ static int __init ib_core_init(void)
err_addr: err_addr:
addr_cleanup(); addr_cleanup();
err_ibnl: err_ibnl:
ibnl_cleanup(); rdma_nl_exit();
err_sysfs: err_sysfs:
class_unregister(&ib_class); class_unregister(&ib_class);
err_comp: err_comp:
...@@ -1191,13 +1237,14 @@ static int __init ib_core_init(void) ...@@ -1191,13 +1237,14 @@ static int __init ib_core_init(void)
static void __exit ib_core_cleanup(void) static void __exit ib_core_cleanup(void)
{ {
unregister_lsm_notifier(&ibdev_lsm_nb);
ib_cache_cleanup(); ib_cache_cleanup();
ib_remove_ibnl_clients(); nldev_exit();
rdma_nl_unregister(RDMA_NL_LS);
unregister_lsm_notifier(&ibdev_lsm_nb);
ib_sa_cleanup(); ib_sa_cleanup();
ib_mad_cleanup(); ib_mad_cleanup();
addr_cleanup(); addr_cleanup();
ibnl_cleanup(); rdma_nl_exit();
class_unregister(&ib_class); class_unregister(&ib_class);
destroy_workqueue(ib_comp_wq); destroy_workqueue(ib_comp_wq);
/* Make sure that any pending umem accounting work is done. */ /* Make sure that any pending umem accounting work is done. */
......
...@@ -80,7 +80,7 @@ const char *__attribute_const__ iwcm_reject_msg(int reason) ...@@ -80,7 +80,7 @@ const char *__attribute_const__ iwcm_reject_msg(int reason)
} }
EXPORT_SYMBOL(iwcm_reject_msg); EXPORT_SYMBOL(iwcm_reject_msg);
static struct ibnl_client_cbs iwcm_nl_cb_table[] = { static struct rdma_nl_cbs iwcm_nl_cb_table[] = {
[RDMA_NL_IWPM_REG_PID] = {.dump = iwpm_register_pid_cb}, [RDMA_NL_IWPM_REG_PID] = {.dump = iwpm_register_pid_cb},
[RDMA_NL_IWPM_ADD_MAPPING] = {.dump = iwpm_add_mapping_cb}, [RDMA_NL_IWPM_ADD_MAPPING] = {.dump = iwpm_add_mapping_cb},
[RDMA_NL_IWPM_QUERY_MAPPING] = {.dump = iwpm_add_and_query_mapping_cb}, [RDMA_NL_IWPM_QUERY_MAPPING] = {.dump = iwpm_add_and_query_mapping_cb},
...@@ -1175,12 +1175,8 @@ static int __init iw_cm_init(void) ...@@ -1175,12 +1175,8 @@ static int __init iw_cm_init(void)
ret = iwpm_init(RDMA_NL_IWCM); ret = iwpm_init(RDMA_NL_IWCM);
if (ret) if (ret)
pr_err("iw_cm: couldn't init iwpm\n"); pr_err("iw_cm: couldn't init iwpm\n");
else
ret = ibnl_add_client(RDMA_NL_IWCM, ARRAY_SIZE(iwcm_nl_cb_table), rdma_nl_register(RDMA_NL_IWCM, iwcm_nl_cb_table);
iwcm_nl_cb_table);
if (ret)
pr_err("iw_cm: couldn't register netlink callbacks\n");
iwcm_wq = alloc_ordered_workqueue("iw_cm_wq", WQ_MEM_RECLAIM); iwcm_wq = alloc_ordered_workqueue("iw_cm_wq", WQ_MEM_RECLAIM);
if (!iwcm_wq) if (!iwcm_wq)
return -ENOMEM; return -ENOMEM;
...@@ -1200,7 +1196,7 @@ static void __exit iw_cm_cleanup(void) ...@@ -1200,7 +1196,7 @@ static void __exit iw_cm_cleanup(void)
{ {
unregister_net_sysctl_table(iwcm_ctl_table_hdr); unregister_net_sysctl_table(iwcm_ctl_table_hdr);
destroy_workqueue(iwcm_wq); destroy_workqueue(iwcm_wq);
ibnl_remove_client(RDMA_NL_IWCM); rdma_nl_unregister(RDMA_NL_IWCM);
iwpm_exit(RDMA_NL_IWCM); iwpm_exit(RDMA_NL_IWCM);
} }
......
...@@ -42,7 +42,6 @@ int iwpm_valid_pid(void) ...@@ -42,7 +42,6 @@ int iwpm_valid_pid(void)
{ {
return iwpm_user_pid > 0; return iwpm_user_pid > 0;
} }
EXPORT_SYMBOL(iwpm_valid_pid);
/* /*
* iwpm_register_pid - Send a netlink query to user space * iwpm_register_pid - Send a netlink query to user space
...@@ -104,7 +103,7 @@ int iwpm_register_pid(struct iwpm_dev_data *pm_msg, u8 nl_client) ...@@ -104,7 +103,7 @@ int iwpm_register_pid(struct iwpm_dev_data *pm_msg, u8 nl_client)
pr_debug("%s: Multicasting a nlmsg (dev = %s ifname = %s iwpm = %s)\n", pr_debug("%s: Multicasting a nlmsg (dev = %s ifname = %s iwpm = %s)\n",
__func__, pm_msg->dev_name, pm_msg->if_name, iwpm_ulib_name); __func__, pm_msg->dev_name, pm_msg->if_name, iwpm_ulib_name);
ret = ibnl_multicast(skb, nlh, RDMA_NL_GROUP_IWPM, GFP_KERNEL); ret = rdma_nl_multicast(skb, RDMA_NL_GROUP_IWPM, GFP_KERNEL);
if (ret) { if (ret) {
skb = NULL; /* skb is freed in the netlink send-op handling */ skb = NULL; /* skb is freed in the netlink send-op handling */
iwpm_user_pid = IWPM_PID_UNAVAILABLE; iwpm_user_pid = IWPM_PID_UNAVAILABLE;
...@@ -122,7 +121,6 @@ int iwpm_register_pid(struct iwpm_dev_data *pm_msg, u8 nl_client) ...@@ -122,7 +121,6 @@ int iwpm_register_pid(struct iwpm_dev_data *pm_msg, u8 nl_client)
iwpm_free_nlmsg_request(&nlmsg_request->kref); iwpm_free_nlmsg_request(&nlmsg_request->kref);
return ret; return ret;
} }
EXPORT_SYMBOL(iwpm_register_pid);
/* /*
* iwpm_add_mapping - Send a netlink add mapping message * iwpm_add_mapping - Send a netlink add mapping message
...@@ -174,7 +172,7 @@ int iwpm_add_mapping(struct iwpm_sa_data *pm_msg, u8 nl_client) ...@@ -174,7 +172,7 @@ int iwpm_add_mapping(struct iwpm_sa_data *pm_msg, u8 nl_client)
goto add_mapping_error; goto add_mapping_error;
nlmsg_request->req_buffer = pm_msg; nlmsg_request->req_buffer = pm_msg;
ret = ibnl_unicast(skb, nlh, iwpm_user_pid); ret = rdma_nl_unicast_wait(skb, iwpm_user_pid);
if (ret) { if (ret) {
skb = NULL; /* skb is freed in the netlink send-op handling */ skb = NULL; /* skb is freed in the netlink send-op handling */
iwpm_user_pid = IWPM_PID_UNDEFINED; iwpm_user_pid = IWPM_PID_UNDEFINED;
...@@ -191,7 +189,6 @@ int iwpm_add_mapping(struct iwpm_sa_data *pm_msg, u8 nl_client) ...@@ -191,7 +189,6 @@ int iwpm_add_mapping(struct iwpm_sa_data *pm_msg, u8 nl_client)
iwpm_free_nlmsg_request(&nlmsg_request->kref); iwpm_free_nlmsg_request(&nlmsg_request->kref);
return ret; return ret;
} }
EXPORT_SYMBOL(iwpm_add_mapping);
/* /*
* iwpm_add_and_query_mapping - Send a netlink add and query * iwpm_add_and_query_mapping - Send a netlink add and query
...@@ -251,7 +248,7 @@ int iwpm_add_and_query_mapping(struct iwpm_sa_data *pm_msg, u8 nl_client) ...@@ -251,7 +248,7 @@ int iwpm_add_and_query_mapping(struct iwpm_sa_data *pm_msg, u8 nl_client)
goto query_mapping_error; goto query_mapping_error;
nlmsg_request->req_buffer = pm_msg; nlmsg_request->req_buffer = pm_msg;
ret = ibnl_unicast(skb, nlh, iwpm_user_pid); ret = rdma_nl_unicast_wait(skb, iwpm_user_pid);
if (ret) { if (ret) {
skb = NULL; /* skb is freed in the netlink send-op handling */ skb = NULL; /* skb is freed in the netlink send-op handling */
err_str = "Unable to send a nlmsg"; err_str = "Unable to send a nlmsg";
...@@ -267,7 +264,6 @@ int iwpm_add_and_query_mapping(struct iwpm_sa_data *pm_msg, u8 nl_client) ...@@ -267,7 +264,6 @@ int iwpm_add_and_query_mapping(struct iwpm_sa_data *pm_msg, u8 nl_client)
iwpm_free_nlmsg_request(&nlmsg_request->kref); iwpm_free_nlmsg_request(&nlmsg_request->kref);
return ret; return ret;
} }
EXPORT_SYMBOL(iwpm_add_and_query_mapping);
/* /*
* iwpm_remove_mapping - Send a netlink remove mapping message * iwpm_remove_mapping - Send a netlink remove mapping message
...@@ -312,7 +308,7 @@ int iwpm_remove_mapping(struct sockaddr_storage *local_addr, u8 nl_client) ...@@ -312,7 +308,7 @@ int iwpm_remove_mapping(struct sockaddr_storage *local_addr, u8 nl_client)
if (ret) if (ret)
goto remove_mapping_error; goto remove_mapping_error;
ret = ibnl_unicast(skb, nlh, iwpm_user_pid); ret = rdma_nl_unicast_wait(skb, iwpm_user_pid);
if (ret) { if (ret) {
skb = NULL; /* skb is freed in the netlink send-op handling */ skb = NULL; /* skb is freed in the netlink send-op handling */
iwpm_user_pid = IWPM_PID_UNDEFINED; iwpm_user_pid = IWPM_PID_UNDEFINED;
...@@ -328,7 +324,6 @@ int iwpm_remove_mapping(struct sockaddr_storage *local_addr, u8 nl_client) ...@@ -328,7 +324,6 @@ int iwpm_remove_mapping(struct sockaddr_storage *local_addr, u8 nl_client)
dev_kfree_skb_any(skb); dev_kfree_skb_any(skb);
return ret; return ret;
} }
EXPORT_SYMBOL(iwpm_remove_mapping);
/* netlink attribute policy for the received response to register pid request */ /* netlink attribute policy for the received response to register pid request */
static const struct nla_policy resp_reg_policy[IWPM_NLA_RREG_PID_MAX] = { static const struct nla_policy resp_reg_policy[IWPM_NLA_RREG_PID_MAX] = {
...@@ -397,7 +392,6 @@ int iwpm_register_pid_cb(struct sk_buff *skb, struct netlink_callback *cb) ...@@ -397,7 +392,6 @@ int iwpm_register_pid_cb(struct sk_buff *skb, struct netlink_callback *cb)
up(&nlmsg_request->sem); up(&nlmsg_request->sem);
return 0; return 0;
} }
EXPORT_SYMBOL(iwpm_register_pid_cb);
/* netlink attribute policy for the received response to add mapping request */ /* netlink attribute policy for the received response to add mapping request */
static const struct nla_policy resp_add_policy[IWPM_NLA_RMANAGE_MAPPING_MAX] = { static const struct nla_policy resp_add_policy[IWPM_NLA_RMANAGE_MAPPING_MAX] = {
...@@ -466,7 +460,6 @@ int iwpm_add_mapping_cb(struct sk_buff *skb, struct netlink_callback *cb) ...@@ -466,7 +460,6 @@ int iwpm_add_mapping_cb(struct sk_buff *skb, struct netlink_callback *cb)
up(&nlmsg_request->sem); up(&nlmsg_request->sem);
return 0; return 0;
} }
EXPORT_SYMBOL(iwpm_add_mapping_cb);
/* netlink attribute policy for the response to add and query mapping request /* netlink attribute policy for the response to add and query mapping request
* and response with remote address info */ * and response with remote address info */
...@@ -558,7 +551,6 @@ int iwpm_add_and_query_mapping_cb(struct sk_buff *skb, ...@@ -558,7 +551,6 @@ int iwpm_add_and_query_mapping_cb(struct sk_buff *skb,
up(&nlmsg_request->sem); up(&nlmsg_request->sem);
return 0; return 0;
} }
EXPORT_SYMBOL(iwpm_add_and_query_mapping_cb);
/* /*
* iwpm_remote_info_cb - Process a port mapper message, containing * iwpm_remote_info_cb - Process a port mapper message, containing
...@@ -627,7 +619,6 @@ int iwpm_remote_info_cb(struct sk_buff *skb, struct netlink_callback *cb) ...@@ -627,7 +619,6 @@ int iwpm_remote_info_cb(struct sk_buff *skb, struct netlink_callback *cb)
"remote_info: Mapped remote sockaddr:"); "remote_info: Mapped remote sockaddr:");
return ret; return ret;
} }
EXPORT_SYMBOL(iwpm_remote_info_cb);
/* netlink attribute policy for the received request for mapping info */ /* netlink attribute policy for the received request for mapping info */
static const struct nla_policy resp_mapinfo_policy[IWPM_NLA_MAPINFO_REQ_MAX] = { static const struct nla_policy resp_mapinfo_policy[IWPM_NLA_MAPINFO_REQ_MAX] = {
...@@ -677,7 +668,6 @@ int iwpm_mapping_info_cb(struct sk_buff *skb, struct netlink_callback *cb) ...@@ -677,7 +668,6 @@ int iwpm_mapping_info_cb(struct sk_buff *skb, struct netlink_callback *cb)
ret = iwpm_send_mapinfo(nl_client, iwpm_user_pid); ret = iwpm_send_mapinfo(nl_client, iwpm_user_pid);
return ret; return ret;
} }
EXPORT_SYMBOL(iwpm_mapping_info_cb);
/* netlink attribute policy for the received mapping info ack */ /* netlink attribute policy for the received mapping info ack */
static const struct nla_policy ack_mapinfo_policy[IWPM_NLA_MAPINFO_NUM_MAX] = { static const struct nla_policy ack_mapinfo_policy[IWPM_NLA_MAPINFO_NUM_MAX] = {
...@@ -707,7 +697,6 @@ int iwpm_ack_mapping_info_cb(struct sk_buff *skb, struct netlink_callback *cb) ...@@ -707,7 +697,6 @@ int iwpm_ack_mapping_info_cb(struct sk_buff *skb, struct netlink_callback *cb)
atomic_set(&echo_nlmsg_seq, cb->nlh->nlmsg_seq); atomic_set(&echo_nlmsg_seq, cb->nlh->nlmsg_seq);
return 0; return 0;
} }
EXPORT_SYMBOL(iwpm_ack_mapping_info_cb);
/* netlink attribute policy for the received port mapper error message */ /* netlink attribute policy for the received port mapper error message */
static const struct nla_policy map_error_policy[IWPM_NLA_ERR_MAX] = { static const struct nla_policy map_error_policy[IWPM_NLA_ERR_MAX] = {
...@@ -751,4 +740,3 @@ int iwpm_mapping_error_cb(struct sk_buff *skb, struct netlink_callback *cb) ...@@ -751,4 +740,3 @@ int iwpm_mapping_error_cb(struct sk_buff *skb, struct netlink_callback *cb)
up(&nlmsg_request->sem); up(&nlmsg_request->sem);
return 0; return 0;
} }
EXPORT_SYMBOL(iwpm_mapping_error_cb);
...@@ -54,8 +54,6 @@ static struct iwpm_admin_data iwpm_admin; ...@@ -54,8 +54,6 @@ static struct iwpm_admin_data iwpm_admin;
int iwpm_init(u8 nl_client) int iwpm_init(u8 nl_client)
{ {
int ret = 0; int ret = 0;
if (iwpm_valid_client(nl_client))
return -EINVAL;
mutex_lock(&iwpm_admin_lock); mutex_lock(&iwpm_admin_lock);
if (atomic_read(&iwpm_admin.refcount) == 0) { if (atomic_read(&iwpm_admin.refcount) == 0) {
iwpm_hash_bucket = kzalloc(IWPM_MAPINFO_HASH_SIZE * iwpm_hash_bucket = kzalloc(IWPM_MAPINFO_HASH_SIZE *
...@@ -83,7 +81,6 @@ int iwpm_init(u8 nl_client) ...@@ -83,7 +81,6 @@ int iwpm_init(u8 nl_client)
} }
return ret; return ret;
} }
EXPORT_SYMBOL(iwpm_init);
static void free_hash_bucket(void); static void free_hash_bucket(void);
static void free_reminfo_bucket(void); static void free_reminfo_bucket(void);
...@@ -109,7 +106,6 @@ int iwpm_exit(u8 nl_client) ...@@ -109,7 +106,6 @@ int iwpm_exit(u8 nl_client)
iwpm_set_registration(nl_client, IWPM_REG_UNDEF); iwpm_set_registration(nl_client, IWPM_REG_UNDEF);
return 0; return 0;
} }
EXPORT_SYMBOL(iwpm_exit);
static struct hlist_head *get_mapinfo_hash_bucket(struct sockaddr_storage *, static struct hlist_head *get_mapinfo_hash_bucket(struct sockaddr_storage *,
struct sockaddr_storage *); struct sockaddr_storage *);
...@@ -148,7 +144,6 @@ int iwpm_create_mapinfo(struct sockaddr_storage *local_sockaddr, ...@@ -148,7 +144,6 @@ int iwpm_create_mapinfo(struct sockaddr_storage *local_sockaddr,
spin_unlock_irqrestore(&iwpm_mapinfo_lock, flags); spin_unlock_irqrestore(&iwpm_mapinfo_lock, flags);
return ret; return ret;
} }
EXPORT_SYMBOL(iwpm_create_mapinfo);
int iwpm_remove_mapinfo(struct sockaddr_storage *local_sockaddr, int iwpm_remove_mapinfo(struct sockaddr_storage *local_sockaddr,
struct sockaddr_storage *mapped_local_addr) struct sockaddr_storage *mapped_local_addr)
...@@ -184,7 +179,6 @@ int iwpm_remove_mapinfo(struct sockaddr_storage *local_sockaddr, ...@@ -184,7 +179,6 @@ int iwpm_remove_mapinfo(struct sockaddr_storage *local_sockaddr,
spin_unlock_irqrestore(&iwpm_mapinfo_lock, flags); spin_unlock_irqrestore(&iwpm_mapinfo_lock, flags);
return ret; return ret;
} }
EXPORT_SYMBOL(iwpm_remove_mapinfo);
static void free_hash_bucket(void) static void free_hash_bucket(void)
{ {
...@@ -297,7 +291,6 @@ int iwpm_get_remote_info(struct sockaddr_storage *mapped_loc_addr, ...@@ -297,7 +291,6 @@ int iwpm_get_remote_info(struct sockaddr_storage *mapped_loc_addr,
spin_unlock_irqrestore(&iwpm_reminfo_lock, flags); spin_unlock_irqrestore(&iwpm_reminfo_lock, flags);
return ret; return ret;
} }
EXPORT_SYMBOL(iwpm_get_remote_info);
struct iwpm_nlmsg_request *iwpm_get_nlmsg_request(__u32 nlmsg_seq, struct iwpm_nlmsg_request *iwpm_get_nlmsg_request(__u32 nlmsg_seq,
u8 nl_client, gfp_t gfp) u8 nl_client, gfp_t gfp)
...@@ -383,15 +376,11 @@ int iwpm_get_nlmsg_seq(void) ...@@ -383,15 +376,11 @@ int iwpm_get_nlmsg_seq(void)
int iwpm_valid_client(u8 nl_client) int iwpm_valid_client(u8 nl_client)
{ {
if (nl_client >= RDMA_NL_NUM_CLIENTS)
return 0;
return iwpm_admin.client_list[nl_client]; return iwpm_admin.client_list[nl_client];
} }
void iwpm_set_valid(u8 nl_client, int valid) void iwpm_set_valid(u8 nl_client, int valid)
{ {
if (nl_client >= RDMA_NL_NUM_CLIENTS)
return;
iwpm_admin.client_list[nl_client] = valid; iwpm_admin.client_list[nl_client] = valid;
} }
...@@ -608,7 +597,7 @@ static int send_mapinfo_num(u32 mapping_num, u8 nl_client, int iwpm_pid) ...@@ -608,7 +597,7 @@ static int send_mapinfo_num(u32 mapping_num, u8 nl_client, int iwpm_pid)
&mapping_num, IWPM_NLA_MAPINFO_SEND_NUM); &mapping_num, IWPM_NLA_MAPINFO_SEND_NUM);
if (ret) if (ret)
goto mapinfo_num_error; goto mapinfo_num_error;
ret = ibnl_unicast(skb, nlh, iwpm_pid); ret = rdma_nl_unicast(skb, iwpm_pid);
if (ret) { if (ret) {
skb = NULL; skb = NULL;
err_str = "Unable to send a nlmsg"; err_str = "Unable to send a nlmsg";
...@@ -637,7 +626,7 @@ static int send_nlmsg_done(struct sk_buff *skb, u8 nl_client, int iwpm_pid) ...@@ -637,7 +626,7 @@ static int send_nlmsg_done(struct sk_buff *skb, u8 nl_client, int iwpm_pid)
return -ENOMEM; return -ENOMEM;
} }
nlh->nlmsg_type = NLMSG_DONE; nlh->nlmsg_type = NLMSG_DONE;
ret = ibnl_unicast(skb, (struct nlmsghdr *)skb->data, iwpm_pid); ret = rdma_nl_unicast(skb, iwpm_pid);
if (ret) if (ret)
pr_warn("%s Unable to send a nlmsg\n", __func__); pr_warn("%s Unable to send a nlmsg\n", __func__);
return ret; return ret;
......
/* /*
* Copyright (c) 2017 Mellanox Technologies Inc. All rights reserved.
* Copyright (c) 2010 Voltaire Inc. All rights reserved. * Copyright (c) 2010 Voltaire Inc. All rights reserved.
* *
* This software is available to you under a choice of one of two * This software is available to you under a choice of one of two
...@@ -39,237 +40,253 @@ ...@@ -39,237 +40,253 @@
#include <rdma/rdma_netlink.h> #include <rdma/rdma_netlink.h>
#include "core_priv.h" #include "core_priv.h"
struct ibnl_client { #include "core_priv.h"
struct list_head list;
int index;
int nops;
const struct ibnl_client_cbs *cb_table;
};
static DEFINE_MUTEX(ibnl_mutex); static DEFINE_MUTEX(rdma_nl_mutex);
static struct sock *nls; static struct sock *nls;
static LIST_HEAD(client_list); static struct {
const struct rdma_nl_cbs *cb_table;
} rdma_nl_types[RDMA_NL_NUM_CLIENTS];
int ibnl_chk_listeners(unsigned int group) int rdma_nl_chk_listeners(unsigned int group)
{ {
if (netlink_has_listeners(nls, group) == 0) return (netlink_has_listeners(nls, group)) ? 0 : -1;
return -1;
return 0;
} }
EXPORT_SYMBOL(rdma_nl_chk_listeners);
int ibnl_add_client(int index, int nops, static bool is_nl_msg_valid(unsigned int type, unsigned int op)
const struct ibnl_client_cbs cb_table[])
{ {
struct ibnl_client *cur; static const unsigned int max_num_ops[RDMA_NL_NUM_CLIENTS - 1] = {
struct ibnl_client *nl_client; RDMA_NL_RDMA_CM_NUM_OPS,
RDMA_NL_IWPM_NUM_OPS,
nl_client = kmalloc(sizeof *nl_client, GFP_KERNEL); 0,
if (!nl_client) RDMA_NL_LS_NUM_OPS,
return -ENOMEM; RDMA_NLDEV_NUM_OPS };
nl_client->index = index; /*
nl_client->nops = nops; * This BUILD_BUG_ON is intended to catch addition of new
nl_client->cb_table = cb_table; * RDMA netlink protocol without updating the array above.
*/
BUILD_BUG_ON(RDMA_NL_NUM_CLIENTS != 6);
mutex_lock(&ibnl_mutex); if (type > RDMA_NL_NUM_CLIENTS - 1)
return false;
list_for_each_entry(cur, &client_list, list) { return (op < max_num_ops[type - 1]) ? true : false;
if (cur->index == index) { }
pr_warn("Client for %d already exists\n", index);
mutex_unlock(&ibnl_mutex);
kfree(nl_client);
return -EINVAL;
}
}
list_add_tail(&nl_client->list, &client_list); static bool is_nl_valid(unsigned int type, unsigned int op)
{
const struct rdma_nl_cbs *cb_table;
mutex_unlock(&ibnl_mutex); if (!is_nl_msg_valid(type, op))
return false;
return 0; cb_table = rdma_nl_types[type].cb_table;
if (!cb_table || (!cb_table[op].dump && !cb_table[op].doit))
return false;
return true;
} }
EXPORT_SYMBOL(ibnl_add_client);
int ibnl_remove_client(int index) void rdma_nl_register(unsigned int index,
const struct rdma_nl_cbs cb_table[])
{ {
struct ibnl_client *cur, *next; mutex_lock(&rdma_nl_mutex);
if (!is_nl_msg_valid(index, 0)) {
mutex_lock(&ibnl_mutex); /*
list_for_each_entry_safe(cur, next, &client_list, list) { * All clients are not interesting in success/failure of
if (cur->index == index) { * this call. They want to see the print to error log and
list_del(&(cur->list)); * continue their initialization. Print warning for them,
mutex_unlock(&ibnl_mutex); * because it is programmer's error to be here.
kfree(cur); */
return 0; mutex_unlock(&rdma_nl_mutex);
} WARN(true,
"The not-valid %u index was supplied to RDMA netlink\n",
index);
return;
} }
pr_warn("Can't remove callback for client idx %d. Not found\n", index);
mutex_unlock(&ibnl_mutex);
return -EINVAL; if (rdma_nl_types[index].cb_table) {
mutex_unlock(&rdma_nl_mutex);
WARN(true,
"The %u index is already registered in RDMA netlink\n",
index);
return;
}
rdma_nl_types[index].cb_table = cb_table;
mutex_unlock(&rdma_nl_mutex);
}
EXPORT_SYMBOL(rdma_nl_register);
void rdma_nl_unregister(unsigned int index)
{
mutex_lock(&rdma_nl_mutex);
rdma_nl_types[index].cb_table = NULL;
mutex_unlock(&rdma_nl_mutex);
} }
EXPORT_SYMBOL(ibnl_remove_client); EXPORT_SYMBOL(rdma_nl_unregister);
void *ibnl_put_msg(struct sk_buff *skb, struct nlmsghdr **nlh, int seq, void *ibnl_put_msg(struct sk_buff *skb, struct nlmsghdr **nlh, int seq,
int len, int client, int op, int flags) int len, int client, int op, int flags)
{ {
unsigned char *prev_tail; *nlh = nlmsg_put(skb, 0, seq, RDMA_NL_GET_TYPE(client, op), len, flags);
prev_tail = skb_tail_pointer(skb);
*nlh = nlmsg_put(skb, 0, seq, RDMA_NL_GET_TYPE(client, op),
len, flags);
if (!*nlh) if (!*nlh)
goto out_nlmsg_trim; return NULL;
(*nlh)->nlmsg_len = skb_tail_pointer(skb) - prev_tail;
return nlmsg_data(*nlh); return nlmsg_data(*nlh);
out_nlmsg_trim:
nlmsg_trim(skb, prev_tail);
return NULL;
} }
EXPORT_SYMBOL(ibnl_put_msg); EXPORT_SYMBOL(ibnl_put_msg);
int ibnl_put_attr(struct sk_buff *skb, struct nlmsghdr *nlh, int ibnl_put_attr(struct sk_buff *skb, struct nlmsghdr *nlh,
int len, void *data, int type) int len, void *data, int type)
{ {
unsigned char *prev_tail; if (nla_put(skb, type, len, data)) {
nlmsg_cancel(skb, nlh);
prev_tail = skb_tail_pointer(skb); return -EMSGSIZE;
if (nla_put(skb, type, len, data)) }
goto nla_put_failure;
nlh->nlmsg_len += skb_tail_pointer(skb) - prev_tail;
return 0; return 0;
nla_put_failure:
nlmsg_trim(skb, prev_tail - nlh->nlmsg_len);
return -EMSGSIZE;
} }
EXPORT_SYMBOL(ibnl_put_attr); EXPORT_SYMBOL(ibnl_put_attr);
static int ibnl_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh, static int rdma_nl_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh,
struct netlink_ext_ack *extack) struct netlink_ext_ack *extack)
{ {
struct ibnl_client *client;
int type = nlh->nlmsg_type; int type = nlh->nlmsg_type;
int index = RDMA_NL_GET_CLIENT(type); unsigned int index = RDMA_NL_GET_CLIENT(type);
unsigned int op = RDMA_NL_GET_OP(type); unsigned int op = RDMA_NL_GET_OP(type);
const struct rdma_nl_cbs *cb_table;
if (!is_nl_valid(index, op))
return -EINVAL;
cb_table = rdma_nl_types[index].cb_table;
list_for_each_entry(client, &client_list, list) { if ((cb_table[op].flags & RDMA_NL_ADMIN_PERM) &&
if (client->index == index) { !netlink_capable(skb, CAP_NET_ADMIN))
if (op >= client->nops || !client->cb_table[op].dump) return -EPERM;
return -EINVAL;
/* FIXME: Convert IWCM to properly handle doit callbacks */
/* if ((nlh->nlmsg_flags & NLM_F_DUMP) || index == RDMA_NL_RDMA_CM ||
* For response or local service set_timeout request, index == RDMA_NL_IWCM) {
* there is no need to use netlink_dump_start. struct netlink_dump_control c = {
*/ .dump = cb_table[op].dump,
if (!(nlh->nlmsg_flags & NLM_F_REQUEST) || };
(index == RDMA_NL_LS && return netlink_dump_start(nls, skb, nlh, &c);
op == RDMA_NL_LS_OP_SET_TIMEOUT)) {
struct netlink_callback cb = {
.skb = skb,
.nlh = nlh,
.dump = client->cb_table[op].dump,
.module = client->cb_table[op].module,
};
return cb.dump(skb, &cb);
}
{
struct netlink_dump_control c = {
.dump = client->cb_table[op].dump,
.module = client->cb_table[op].module,
};
return netlink_dump_start(nls, skb, nlh, &c);
}
}
} }
pr_info("Index %d wasn't found in client list\n", index); if (cb_table[op].doit)
return -EINVAL; return cb_table[op].doit(skb, nlh, extack);
return 0;
} }
static void ibnl_rcv_reply_skb(struct sk_buff *skb) /*
* This function is similar to netlink_rcv_skb with one exception:
* It calls to the callback for the netlink messages without NLM_F_REQUEST
* flag. These messages are intended for RDMA_NL_LS consumer, so it is allowed
* for that consumer only.
*/
static int rdma_nl_rcv_skb(struct sk_buff *skb, int (*cb)(struct sk_buff *,
struct nlmsghdr *,
struct netlink_ext_ack *))
{ {
struct netlink_ext_ack extack = {};
struct nlmsghdr *nlh; struct nlmsghdr *nlh;
int msglen; int err;
/*
* Process responses until there is no more message or the first
* request. Generally speaking, it is not recommended to mix responses
* with requests.
*/
while (skb->len >= nlmsg_total_size(0)) { while (skb->len >= nlmsg_total_size(0)) {
int msglen;
nlh = nlmsg_hdr(skb); nlh = nlmsg_hdr(skb);
err = 0;
if (nlh->nlmsg_len < NLMSG_HDRLEN || skb->len < nlh->nlmsg_len) if (nlh->nlmsg_len < NLMSG_HDRLEN || skb->len < nlh->nlmsg_len)
return; return 0;
/* Handle response only */
if (nlh->nlmsg_flags & NLM_F_REQUEST)
return;
ibnl_rcv_msg(skb, nlh, NULL);
/*
* Generally speaking, the only requests are handled
* by the kernel, but RDMA_NL_LS is different, because it
* runs backward netlink scheme. Kernel initiates messages
* and waits for reply with data to keep pathrecord cache
* in sync.
*/
if (!(nlh->nlmsg_flags & NLM_F_REQUEST) &&
(RDMA_NL_GET_CLIENT(nlh->nlmsg_type) != RDMA_NL_LS))
goto ack;
/* Skip control messages */
if (nlh->nlmsg_type < NLMSG_MIN_TYPE)
goto ack;
err = cb(skb, nlh, &extack);
if (err == -EINTR)
goto skip;
ack:
if (nlh->nlmsg_flags & NLM_F_ACK || err)
netlink_ack(skb, nlh, err, &extack);
skip:
msglen = NLMSG_ALIGN(nlh->nlmsg_len); msglen = NLMSG_ALIGN(nlh->nlmsg_len);
if (msglen > skb->len) if (msglen > skb->len)
msglen = skb->len; msglen = skb->len;
skb_pull(skb, msglen); skb_pull(skb, msglen);
} }
return 0;
} }
static void ibnl_rcv(struct sk_buff *skb) static void rdma_nl_rcv(struct sk_buff *skb)
{ {
mutex_lock(&ibnl_mutex); mutex_lock(&rdma_nl_mutex);
ibnl_rcv_reply_skb(skb); rdma_nl_rcv_skb(skb, &rdma_nl_rcv_msg);
netlink_rcv_skb(skb, &ibnl_rcv_msg); mutex_unlock(&rdma_nl_mutex);
mutex_unlock(&ibnl_mutex);
} }
int ibnl_unicast(struct sk_buff *skb, struct nlmsghdr *nlh, int rdma_nl_unicast(struct sk_buff *skb, u32 pid)
__u32 pid) {
int err;
err = netlink_unicast(nls, skb, pid, MSG_DONTWAIT);
return (err < 0) ? err : 0;
}
EXPORT_SYMBOL(rdma_nl_unicast);
int rdma_nl_unicast_wait(struct sk_buff *skb, __u32 pid)
{ {
int err; int err;
err = netlink_unicast(nls, skb, pid, 0); err = netlink_unicast(nls, skb, pid, 0);
return (err < 0) ? err : 0; return (err < 0) ? err : 0;
} }
EXPORT_SYMBOL(ibnl_unicast); EXPORT_SYMBOL(rdma_nl_unicast_wait);
int ibnl_multicast(struct sk_buff *skb, struct nlmsghdr *nlh, int rdma_nl_multicast(struct sk_buff *skb, unsigned int group, gfp_t flags)
unsigned int group, gfp_t flags)
{ {
return nlmsg_multicast(nls, skb, 0, group, flags); return nlmsg_multicast(nls, skb, 0, group, flags);
} }
EXPORT_SYMBOL(ibnl_multicast); EXPORT_SYMBOL(rdma_nl_multicast);
int __init ibnl_init(void) int __init rdma_nl_init(void)
{ {
struct netlink_kernel_cfg cfg = { struct netlink_kernel_cfg cfg = {
.input = ibnl_rcv, .input = rdma_nl_rcv,
}; };
nls = netlink_kernel_create(&init_net, NETLINK_RDMA, &cfg); nls = netlink_kernel_create(&init_net, NETLINK_RDMA, &cfg);
if (!nls) { if (!nls)
pr_warn("Failed to create netlink socket\n");
return -ENOMEM; return -ENOMEM;
}
nls->sk_sndtimeo = 10 * HZ; nls->sk_sndtimeo = 10 * HZ;
return 0; return 0;
} }
void ibnl_cleanup(void) void rdma_nl_exit(void)
{ {
struct ibnl_client *cur, *next; int idx;
mutex_lock(&ibnl_mutex); for (idx = 0; idx < RDMA_NL_NUM_CLIENTS; idx++)
list_for_each_entry_safe(cur, next, &client_list, list) { rdma_nl_unregister(idx);
list_del(&(cur->list));
kfree(cur);
}
mutex_unlock(&ibnl_mutex);
netlink_kernel_release(nls); netlink_kernel_release(nls);
} }
/*
* Copyright (c) 2017 Mellanox Technologies. All rights reserved.
*
* 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.
*/
#include <net/netlink.h>
#include <rdma/rdma_netlink.h>
#include "core_priv.h"
static const struct nla_policy nldev_policy[RDMA_NLDEV_ATTR_MAX] = {
[RDMA_NLDEV_ATTR_DEV_INDEX] = { .type = NLA_U32 },
[RDMA_NLDEV_ATTR_DEV_NAME] = { .type = NLA_NUL_STRING,
.len = IB_DEVICE_NAME_MAX - 1},
[RDMA_NLDEV_ATTR_PORT_INDEX] = { .type = NLA_U32 },
[RDMA_NLDEV_ATTR_FW_VERSION] = { .type = NLA_NUL_STRING,
.len = IB_FW_VERSION_NAME_MAX - 1},
[RDMA_NLDEV_ATTR_NODE_GUID] = { .type = NLA_U64 },
[RDMA_NLDEV_ATTR_SYS_IMAGE_GUID] = { .type = NLA_U64 },
[RDMA_NLDEV_ATTR_SUBNET_PREFIX] = { .type = NLA_U64 },
[RDMA_NLDEV_ATTR_LID] = { .type = NLA_U32 },
[RDMA_NLDEV_ATTR_SM_LID] = { .type = NLA_U32 },
[RDMA_NLDEV_ATTR_LMC] = { .type = NLA_U8 },
[RDMA_NLDEV_ATTR_PORT_STATE] = { .type = NLA_U8 },
[RDMA_NLDEV_ATTR_PORT_PHYS_STATE] = { .type = NLA_U8 },
[RDMA_NLDEV_ATTR_DEV_NODE_TYPE] = { .type = NLA_U8 },
};
static int fill_dev_info(struct sk_buff *msg, struct ib_device *device)
{
char fw[IB_FW_VERSION_NAME_MAX];
if (nla_put_u32(msg, RDMA_NLDEV_ATTR_DEV_INDEX, device->index))
return -EMSGSIZE;
if (nla_put_string(msg, RDMA_NLDEV_ATTR_DEV_NAME, device->name))
return -EMSGSIZE;
if (nla_put_u32(msg, RDMA_NLDEV_ATTR_PORT_INDEX, rdma_end_port(device)))
return -EMSGSIZE;
BUILD_BUG_ON(sizeof(device->attrs.device_cap_flags) != sizeof(u64));
if (nla_put_u64_64bit(msg, RDMA_NLDEV_ATTR_CAP_FLAGS,
device->attrs.device_cap_flags, 0))
return -EMSGSIZE;
ib_get_device_fw_str(device, fw);
/* Device without FW has strlen(fw) */
if (strlen(fw) && nla_put_string(msg, RDMA_NLDEV_ATTR_FW_VERSION, fw))
return -EMSGSIZE;
if (nla_put_u64_64bit(msg, RDMA_NLDEV_ATTR_NODE_GUID,
be64_to_cpu(device->node_guid), 0))
return -EMSGSIZE;
if (nla_put_u64_64bit(msg, RDMA_NLDEV_ATTR_SYS_IMAGE_GUID,
be64_to_cpu(device->attrs.sys_image_guid), 0))
return -EMSGSIZE;
if (nla_put_u8(msg, RDMA_NLDEV_ATTR_DEV_NODE_TYPE, device->node_type))
return -EMSGSIZE;
return 0;
}
static int fill_port_info(struct sk_buff *msg,
struct ib_device *device, u32 port)
{
struct ib_port_attr attr;
int ret;
if (nla_put_u32(msg, RDMA_NLDEV_ATTR_DEV_INDEX, device->index))
return -EMSGSIZE;
if (nla_put_string(msg, RDMA_NLDEV_ATTR_DEV_NAME, device->name))
return -EMSGSIZE;
if (nla_put_u32(msg, RDMA_NLDEV_ATTR_PORT_INDEX, port))
return -EMSGSIZE;
ret = ib_query_port(device, port, &attr);
if (ret)
return ret;
BUILD_BUG_ON(sizeof(attr.port_cap_flags) > sizeof(u64));
if (nla_put_u64_64bit(msg, RDMA_NLDEV_ATTR_CAP_FLAGS,
(u64)attr.port_cap_flags, 0))
return -EMSGSIZE;
if (rdma_protocol_ib(device, port) &&
nla_put_u64_64bit(msg, RDMA_NLDEV_ATTR_SUBNET_PREFIX,
attr.subnet_prefix, 0))
return -EMSGSIZE;
if (rdma_protocol_ib(device, port)) {
if (nla_put_u32(msg, RDMA_NLDEV_ATTR_LID, attr.lid))
return -EMSGSIZE;
if (nla_put_u32(msg, RDMA_NLDEV_ATTR_SM_LID, attr.sm_lid))
return -EMSGSIZE;
if (nla_put_u8(msg, RDMA_NLDEV_ATTR_LMC, attr.lmc))
return -EMSGSIZE;
}
if (nla_put_u8(msg, RDMA_NLDEV_ATTR_PORT_STATE, attr.state))
return -EMSGSIZE;
if (nla_put_u8(msg, RDMA_NLDEV_ATTR_PORT_PHYS_STATE, attr.phys_state))
return -EMSGSIZE;
return 0;
}
static int nldev_get_doit(struct sk_buff *skb, struct nlmsghdr *nlh,
struct netlink_ext_ack *extack)
{
struct nlattr *tb[RDMA_NLDEV_ATTR_MAX];
struct ib_device *device;
struct sk_buff *msg;
u32 index;
int err;
err = nlmsg_parse(nlh, 0, tb, RDMA_NLDEV_ATTR_MAX - 1,
nldev_policy, extack);
if (err || !tb[RDMA_NLDEV_ATTR_DEV_INDEX])
return -EINVAL;
index = nla_get_u32(tb[RDMA_NLDEV_ATTR_DEV_INDEX]);
device = __ib_device_get_by_index(index);
if (!device)
return -EINVAL;
msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
if (!msg)
return -ENOMEM;
nlh = nlmsg_put(msg, NETLINK_CB(skb).portid, nlh->nlmsg_seq,
RDMA_NL_GET_TYPE(RDMA_NL_NLDEV, RDMA_NLDEV_CMD_GET),
0, 0);
err = fill_dev_info(msg, device);
if (err) {
nlmsg_free(msg);
return err;
}
nlmsg_end(msg, nlh);
return rdma_nl_unicast(msg, NETLINK_CB(skb).portid);
}
static int _nldev_get_dumpit(struct ib_device *device,
struct sk_buff *skb,
struct netlink_callback *cb,
unsigned int idx)
{
int start = cb->args[0];
struct nlmsghdr *nlh;
if (idx < start)
return 0;
nlh = nlmsg_put(skb, NETLINK_CB(cb->skb).portid, cb->nlh->nlmsg_seq,
RDMA_NL_GET_TYPE(RDMA_NL_NLDEV, RDMA_NLDEV_CMD_GET),
0, NLM_F_MULTI);
if (fill_dev_info(skb, device)) {
nlmsg_cancel(skb, nlh);
goto out;
}
nlmsg_end(skb, nlh);
idx++;
out: cb->args[0] = idx;
return skb->len;
}
static int nldev_get_dumpit(struct sk_buff *skb, struct netlink_callback *cb)
{
/*
* There is no need to take lock, because
* we are relying on ib_core's lists_rwsem
*/
return ib_enum_all_devs(_nldev_get_dumpit, skb, cb);
}
static int nldev_port_get_doit(struct sk_buff *skb, struct nlmsghdr *nlh,
struct netlink_ext_ack *extack)
{
struct nlattr *tb[RDMA_NLDEV_ATTR_MAX];
struct ib_device *device;
struct sk_buff *msg;
u32 index;
u32 port;
int err;
err = nlmsg_parse(nlh, 0, tb, RDMA_NLDEV_ATTR_MAX - 1,
nldev_policy, extack);
if (err || !tb[RDMA_NLDEV_ATTR_PORT_INDEX])
return -EINVAL;
index = nla_get_u32(tb[RDMA_NLDEV_ATTR_DEV_INDEX]);
device = __ib_device_get_by_index(index);
if (!device)
return -EINVAL;
port = nla_get_u32(tb[RDMA_NLDEV_ATTR_PORT_INDEX]);
if (!rdma_is_port_valid(device, port))
return -EINVAL;
msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
if (!msg)
return -ENOMEM;
nlh = nlmsg_put(msg, NETLINK_CB(skb).portid, nlh->nlmsg_seq,
RDMA_NL_GET_TYPE(RDMA_NL_NLDEV, RDMA_NLDEV_CMD_GET),
0, 0);
err = fill_port_info(msg, device, port);
if (err) {
nlmsg_free(msg);
return err;
}
nlmsg_end(msg, nlh);
return rdma_nl_unicast(msg, NETLINK_CB(skb).portid);
}
static int nldev_port_get_dumpit(struct sk_buff *skb,
struct netlink_callback *cb)
{
struct nlattr *tb[RDMA_NLDEV_ATTR_MAX];
struct ib_device *device;
int start = cb->args[0];
struct nlmsghdr *nlh;
u32 idx = 0;
u32 ifindex;
int err;
u32 p;
err = nlmsg_parse(cb->nlh, 0, tb, RDMA_NLDEV_ATTR_MAX - 1,
nldev_policy, NULL);
if (err || !tb[RDMA_NLDEV_ATTR_DEV_INDEX])
return -EINVAL;
ifindex = nla_get_u32(tb[RDMA_NLDEV_ATTR_DEV_INDEX]);
device = __ib_device_get_by_index(ifindex);
if (!device)
return -EINVAL;
for (p = rdma_start_port(device); p <= rdma_end_port(device); ++p) {
/*
* The dumpit function returns all information from specific
* index. This specific index is taken from the netlink
* messages request sent by user and it is available
* in cb->args[0].
*
* Usually, the user doesn't fill this field and it causes
* to return everything.
*
*/
if (idx < start) {
idx++;
continue;
}
nlh = nlmsg_put(skb, NETLINK_CB(cb->skb).portid,
cb->nlh->nlmsg_seq,
RDMA_NL_GET_TYPE(RDMA_NL_NLDEV,
RDMA_NLDEV_CMD_PORT_GET),
0, NLM_F_MULTI);
if (fill_port_info(skb, device, p)) {
nlmsg_cancel(skb, nlh);
goto out;
}
idx++;
nlmsg_end(skb, nlh);
}
out: cb->args[0] = idx;
return skb->len;
}
static const struct rdma_nl_cbs nldev_cb_table[] = {
[RDMA_NLDEV_CMD_GET] = {
.doit = nldev_get_doit,
.dump = nldev_get_dumpit,
},
[RDMA_NLDEV_CMD_PORT_GET] = {
.doit = nldev_port_get_doit,
.dump = nldev_port_get_dumpit,
},
};
void __init nldev_init(void)
{
rdma_nl_register(RDMA_NL_NLDEV, nldev_cb_table);
}
void __exit nldev_exit(void)
{
rdma_nl_unregister(RDMA_NL_NLDEV);
}
...@@ -44,6 +44,8 @@ ...@@ -44,6 +44,8 @@
static struct workqueue_struct *gid_cache_wq; static struct workqueue_struct *gid_cache_wq;
static struct workqueue_struct *gid_cache_wq;
enum gid_op_type { enum gid_op_type {
GID_DEL = 0, GID_DEL = 0,
GID_ADD GID_ADD
......
...@@ -861,7 +861,7 @@ static int ib_nl_send_msg(struct ib_sa_query *query, gfp_t gfp_mask) ...@@ -861,7 +861,7 @@ static int ib_nl_send_msg(struct ib_sa_query *query, gfp_t gfp_mask)
/* Repair the nlmsg header length */ /* Repair the nlmsg header length */
nlmsg_end(skb, nlh); nlmsg_end(skb, nlh);
ret = ibnl_multicast(skb, nlh, RDMA_NL_GROUP_LS, gfp_mask); ret = rdma_nl_multicast(skb, RDMA_NL_GROUP_LS, gfp_mask);
if (!ret) if (!ret)
ret = len; ret = len;
else else
...@@ -1021,9 +1021,9 @@ static void ib_nl_request_timeout(struct work_struct *work) ...@@ -1021,9 +1021,9 @@ static void ib_nl_request_timeout(struct work_struct *work)
} }
int ib_nl_handle_set_timeout(struct sk_buff *skb, int ib_nl_handle_set_timeout(struct sk_buff *skb,
struct netlink_callback *cb) struct nlmsghdr *nlh,
struct netlink_ext_ack *extack)
{ {
const struct nlmsghdr *nlh = (struct nlmsghdr *)cb->nlh;
int timeout, delta, abs_delta; int timeout, delta, abs_delta;
const struct nlattr *attr; const struct nlattr *attr;
unsigned long flags; unsigned long flags;
...@@ -1033,8 +1033,7 @@ int ib_nl_handle_set_timeout(struct sk_buff *skb, ...@@ -1033,8 +1033,7 @@ int ib_nl_handle_set_timeout(struct sk_buff *skb,
int ret; int ret;
if (!(nlh->nlmsg_flags & NLM_F_REQUEST) || if (!(nlh->nlmsg_flags & NLM_F_REQUEST) ||
!(NETLINK_CB(skb).sk) || !(NETLINK_CB(skb).sk))
!netlink_capable(skb, CAP_NET_ADMIN))
return -EPERM; return -EPERM;
ret = nla_parse(tb, LS_NLA_TYPE_MAX - 1, nlmsg_data(nlh), ret = nla_parse(tb, LS_NLA_TYPE_MAX - 1, nlmsg_data(nlh),
...@@ -1098,9 +1097,9 @@ static inline int ib_nl_is_good_resolve_resp(const struct nlmsghdr *nlh) ...@@ -1098,9 +1097,9 @@ static inline int ib_nl_is_good_resolve_resp(const struct nlmsghdr *nlh)
} }
int ib_nl_handle_resolve_resp(struct sk_buff *skb, int ib_nl_handle_resolve_resp(struct sk_buff *skb,
struct netlink_callback *cb) struct nlmsghdr *nlh,
struct netlink_ext_ack *extack)
{ {
const struct nlmsghdr *nlh = (struct nlmsghdr *)cb->nlh;
unsigned long flags; unsigned long flags;
struct ib_sa_query *query; struct ib_sa_query *query;
struct ib_mad_send_buf *send_buf; struct ib_mad_send_buf *send_buf;
...@@ -1109,8 +1108,7 @@ int ib_nl_handle_resolve_resp(struct sk_buff *skb, ...@@ -1109,8 +1108,7 @@ int ib_nl_handle_resolve_resp(struct sk_buff *skb,
int ret; int ret;
if ((nlh->nlmsg_flags & NLM_F_REQUEST) || if ((nlh->nlmsg_flags & NLM_F_REQUEST) ||
!(NETLINK_CB(skb).sk) || !(NETLINK_CB(skb).sk))
!netlink_capable(skb, CAP_NET_ADMIN))
return -EPERM; return -EPERM;
spin_lock_irqsave(&ib_nl_request_lock, flags); spin_lock_irqsave(&ib_nl_request_lock, flags);
...@@ -1420,7 +1418,7 @@ static int send_mad(struct ib_sa_query *query, int timeout_ms, gfp_t gfp_mask) ...@@ -1420,7 +1418,7 @@ static int send_mad(struct ib_sa_query *query, int timeout_ms, gfp_t gfp_mask)
if ((query->flags & IB_SA_ENABLE_LOCAL_SERVICE) && if ((query->flags & IB_SA_ENABLE_LOCAL_SERVICE) &&
(!(query->flags & IB_SA_QUERY_OPA))) { (!(query->flags & IB_SA_QUERY_OPA))) {
if (!ibnl_chk_listeners(RDMA_NL_GROUP_LS)) { if (!rdma_nl_chk_listeners(RDMA_NL_GROUP_LS)) {
if (!ib_nl_make_request(query, gfp_mask)) if (!ib_nl_make_request(query, gfp_mask))
return id; return id;
} }
......
...@@ -1210,8 +1210,8 @@ static ssize_t show_fw_ver(struct device *device, struct device_attribute *attr, ...@@ -1210,8 +1210,8 @@ static ssize_t show_fw_ver(struct device *device, struct device_attribute *attr,
{ {
struct ib_device *dev = container_of(device, struct ib_device, dev); struct ib_device *dev = container_of(device, struct ib_device, dev);
ib_get_device_fw_str(dev, buf, PAGE_SIZE); ib_get_device_fw_str(dev, buf);
strlcat(buf, "\n", PAGE_SIZE); strlcat(buf, "\n", IB_FW_VERSION_NAME_MAX);
return strlen(buf); return strlen(buf);
} }
......
...@@ -1383,8 +1383,9 @@ static int create_qp(struct ib_uverbs_file *file, ...@@ -1383,8 +1383,9 @@ static int create_qp(struct ib_uverbs_file *file,
attr.rwq_ind_tbl = ind_tbl; attr.rwq_ind_tbl = ind_tbl;
} }
if ((cmd_sz >= offsetof(typeof(*cmd), reserved1) + if (cmd_sz > sizeof(*cmd) &&
sizeof(cmd->reserved1)) && cmd->reserved1) { !ib_is_udata_cleared(ucore, sizeof(*cmd),
cmd_sz - sizeof(*cmd))) {
ret = -EOPNOTSUPP; ret = -EOPNOTSUPP;
goto err_put; goto err_put;
} }
...@@ -1482,11 +1483,21 @@ static int create_qp(struct ib_uverbs_file *file, ...@@ -1482,11 +1483,21 @@ static int create_qp(struct ib_uverbs_file *file,
IB_QP_CREATE_MANAGED_SEND | IB_QP_CREATE_MANAGED_SEND |
IB_QP_CREATE_MANAGED_RECV | IB_QP_CREATE_MANAGED_RECV |
IB_QP_CREATE_SCATTER_FCS | IB_QP_CREATE_SCATTER_FCS |
IB_QP_CREATE_CVLAN_STRIPPING)) { IB_QP_CREATE_CVLAN_STRIPPING |
IB_QP_CREATE_SOURCE_QPN)) {
ret = -EINVAL; ret = -EINVAL;
goto err_put; goto err_put;
} }
if (attr.create_flags & IB_QP_CREATE_SOURCE_QPN) {
if (!capable(CAP_NET_RAW)) {
ret = -EPERM;
goto err_put;
}
attr.source_qpn = cmd->source_qpn;
}
buf = (void *)cmd + sizeof(*cmd); buf = (void *)cmd + sizeof(*cmd);
if (cmd_sz > sizeof(*cmd)) if (cmd_sz > sizeof(*cmd))
if (!(buf[0] == 0 && !memcmp(buf, buf + 1, if (!(buf[0] == 0 && !memcmp(buf, buf + 1,
......
...@@ -1244,6 +1244,18 @@ int ib_resolve_eth_dmac(struct ib_device *device, ...@@ -1244,6 +1244,18 @@ int ib_resolve_eth_dmac(struct ib_device *device,
if (rdma_link_local_addr((struct in6_addr *)grh->dgid.raw)) { if (rdma_link_local_addr((struct in6_addr *)grh->dgid.raw)) {
rdma_get_ll_mac((struct in6_addr *)grh->dgid.raw, rdma_get_ll_mac((struct in6_addr *)grh->dgid.raw,
ah_attr->roce.dmac); ah_attr->roce.dmac);
return 0;
}
if (rdma_is_multicast_addr((struct in6_addr *)ah_attr->grh.dgid.raw)) {
if (ipv6_addr_v4mapped((struct in6_addr *)ah_attr->grh.dgid.raw)) {
__be32 addr = 0;
memcpy(&addr, ah_attr->grh.dgid.raw + 12, 4);
ip_eth_mc_map(addr, (char *)ah_attr->roce.dmac);
} else {
ipv6_eth_mc_map((struct in6_addr *)ah_attr->grh.dgid.raw,
(char *)ah_attr->roce.dmac);
}
} else { } else {
union ib_gid sgid; union ib_gid sgid;
struct ib_gid_attr sgid_attr; struct ib_gid_attr sgid_attr;
...@@ -1302,6 +1314,61 @@ int ib_modify_qp_with_udata(struct ib_qp *qp, struct ib_qp_attr *attr, ...@@ -1302,6 +1314,61 @@ int ib_modify_qp_with_udata(struct ib_qp *qp, struct ib_qp_attr *attr,
} }
EXPORT_SYMBOL(ib_modify_qp_with_udata); EXPORT_SYMBOL(ib_modify_qp_with_udata);
int ib_get_eth_speed(struct ib_device *dev, u8 port_num, u8 *speed, u8 *width)
{
int rc;
u32 netdev_speed;
struct net_device *netdev;
struct ethtool_link_ksettings lksettings;
if (rdma_port_get_link_layer(dev, port_num) != IB_LINK_LAYER_ETHERNET)
return -EINVAL;
if (!dev->get_netdev)
return -EOPNOTSUPP;
netdev = dev->get_netdev(dev, port_num);
if (!netdev)
return -ENODEV;
rtnl_lock();
rc = __ethtool_get_link_ksettings(netdev, &lksettings);
rtnl_unlock();
dev_put(netdev);
if (!rc) {
netdev_speed = lksettings.base.speed;
} else {
netdev_speed = SPEED_1000;
pr_warn("%s speed is unknown, defaulting to %d\n", netdev->name,
netdev_speed);
}
if (netdev_speed <= SPEED_1000) {
*width = IB_WIDTH_1X;
*speed = IB_SPEED_SDR;
} else if (netdev_speed <= SPEED_10000) {
*width = IB_WIDTH_1X;
*speed = IB_SPEED_FDR10;
} else if (netdev_speed <= SPEED_20000) {
*width = IB_WIDTH_4X;
*speed = IB_SPEED_DDR;
} else if (netdev_speed <= SPEED_25000) {
*width = IB_WIDTH_1X;
*speed = IB_SPEED_EDR;
} else if (netdev_speed <= SPEED_40000) {
*width = IB_WIDTH_4X;
*speed = IB_SPEED_FDR10;
} else {
*width = IB_WIDTH_4X;
*speed = IB_SPEED_EDR;
}
return 0;
}
EXPORT_SYMBOL(ib_get_eth_speed);
int ib_modify_qp(struct ib_qp *qp, int ib_modify_qp(struct ib_qp *qp,
struct ib_qp_attr *qp_attr, struct ib_qp_attr *qp_attr,
int qp_attr_mask) int qp_attr_mask)
...@@ -1569,15 +1636,53 @@ EXPORT_SYMBOL(ib_dealloc_fmr); ...@@ -1569,15 +1636,53 @@ EXPORT_SYMBOL(ib_dealloc_fmr);
/* Multicast groups */ /* Multicast groups */
static bool is_valid_mcast_lid(struct ib_qp *qp, u16 lid)
{
struct ib_qp_init_attr init_attr = {};
struct ib_qp_attr attr = {};
int num_eth_ports = 0;
int port;
/* If QP state >= init, it is assigned to a port and we can check this
* port only.
*/
if (!ib_query_qp(qp, &attr, IB_QP_STATE | IB_QP_PORT, &init_attr)) {
if (attr.qp_state >= IB_QPS_INIT) {
if (qp->device->get_link_layer(qp->device, attr.port_num) !=
IB_LINK_LAYER_INFINIBAND)
return true;
goto lid_check;
}
}
/* Can't get a quick answer, iterate over all ports */
for (port = 0; port < qp->device->phys_port_cnt; port++)
if (qp->device->get_link_layer(qp->device, port) !=
IB_LINK_LAYER_INFINIBAND)
num_eth_ports++;
/* If we have at lease one Ethernet port, RoCE annex declares that
* multicast LID should be ignored. We can't tell at this step if the
* QP belongs to an IB or Ethernet port.
*/
if (num_eth_ports)
return true;
/* If all the ports are IB, we can check according to IB spec. */
lid_check:
return !(lid < be16_to_cpu(IB_MULTICAST_LID_BASE) ||
lid == be16_to_cpu(IB_LID_PERMISSIVE));
}
int ib_attach_mcast(struct ib_qp *qp, union ib_gid *gid, u16 lid) int ib_attach_mcast(struct ib_qp *qp, union ib_gid *gid, u16 lid)
{ {
int ret; int ret;
if (!qp->device->attach_mcast) if (!qp->device->attach_mcast)
return -ENOSYS; return -ENOSYS;
if (gid->raw[0] != 0xff || qp->qp_type != IB_QPT_UD ||
lid < be16_to_cpu(IB_MULTICAST_LID_BASE) || if (!rdma_is_multicast_addr((struct in6_addr *)gid->raw) ||
lid == be16_to_cpu(IB_LID_PERMISSIVE)) qp->qp_type != IB_QPT_UD || !is_valid_mcast_lid(qp, lid))
return -EINVAL; return -EINVAL;
ret = qp->device->attach_mcast(qp, gid, lid); ret = qp->device->attach_mcast(qp, gid, lid);
...@@ -1593,9 +1698,9 @@ int ib_detach_mcast(struct ib_qp *qp, union ib_gid *gid, u16 lid) ...@@ -1593,9 +1698,9 @@ int ib_detach_mcast(struct ib_qp *qp, union ib_gid *gid, u16 lid)
if (!qp->device->detach_mcast) if (!qp->device->detach_mcast)
return -ENOSYS; return -ENOSYS;
if (gid->raw[0] != 0xff || qp->qp_type != IB_QPT_UD ||
lid < be16_to_cpu(IB_MULTICAST_LID_BASE) || if (!rdma_is_multicast_addr((struct in6_addr *)gid->raw) ||
lid == be16_to_cpu(IB_LID_PERMISSIVE)) qp->qp_type != IB_QPT_UD || !is_valid_mcast_lid(qp, lid))
return -EINVAL; return -EINVAL;
ret = qp->device->detach_mcast(qp, gid, lid); ret = qp->device->detach_mcast(qp, gid, lid);
......
...@@ -223,50 +223,6 @@ int bnxt_re_modify_device(struct ib_device *ibdev, ...@@ -223,50 +223,6 @@ int bnxt_re_modify_device(struct ib_device *ibdev,
return 0; return 0;
} }
static void __to_ib_speed_width(struct net_device *netdev, u8 *speed, u8 *width)
{
struct ethtool_link_ksettings lksettings;
u32 espeed;
if (netdev->ethtool_ops && netdev->ethtool_ops->get_link_ksettings) {
memset(&lksettings, 0, sizeof(lksettings));
rtnl_lock();
netdev->ethtool_ops->get_link_ksettings(netdev, &lksettings);
rtnl_unlock();
espeed = lksettings.base.speed;
} else {
espeed = SPEED_UNKNOWN;
}
switch (espeed) {
case SPEED_1000:
*speed = IB_SPEED_SDR;
*width = IB_WIDTH_1X;
break;
case SPEED_10000:
*speed = IB_SPEED_QDR;
*width = IB_WIDTH_1X;
break;
case SPEED_20000:
*speed = IB_SPEED_DDR;
*width = IB_WIDTH_4X;
break;
case SPEED_25000:
*speed = IB_SPEED_EDR;
*width = IB_WIDTH_1X;
break;
case SPEED_40000:
*speed = IB_SPEED_QDR;
*width = IB_WIDTH_4X;
break;
case SPEED_50000:
break;
default:
*speed = IB_SPEED_SDR;
*width = IB_WIDTH_1X;
break;
}
}
/* Port */ /* Port */
int bnxt_re_query_port(struct ib_device *ibdev, u8 port_num, int bnxt_re_query_port(struct ib_device *ibdev, u8 port_num,
struct ib_port_attr *port_attr) struct ib_port_attr *port_attr)
...@@ -308,25 +264,9 @@ int bnxt_re_query_port(struct ib_device *ibdev, u8 port_num, ...@@ -308,25 +264,9 @@ int bnxt_re_query_port(struct ib_device *ibdev, u8 port_num,
* IB stack to avoid race in the NETDEV_UNREG path * IB stack to avoid race in the NETDEV_UNREG path
*/ */
if (test_bit(BNXT_RE_FLAG_IBDEV_REGISTERED, &rdev->flags)) if (test_bit(BNXT_RE_FLAG_IBDEV_REGISTERED, &rdev->flags))
__to_ib_speed_width(rdev->netdev, &port_attr->active_speed, if (!ib_get_eth_speed(ibdev, port_num, &port_attr->active_speed,
&port_attr->active_width); &port_attr->active_width))
return 0; return -EINVAL;
}
int bnxt_re_modify_port(struct ib_device *ibdev, u8 port_num,
int port_modify_mask,
struct ib_port_modify *port_modify)
{
switch (port_modify_mask) {
case IB_PORT_SHUTDOWN:
break;
case IB_PORT_INIT_TYPE:
break;
case IB_PORT_RESET_QKEY_CNTR:
break;
default:
break;
}
return 0; return 0;
} }
...@@ -846,6 +786,7 @@ int bnxt_re_destroy_qp(struct ib_qp *ib_qp) ...@@ -846,6 +786,7 @@ int bnxt_re_destroy_qp(struct ib_qp *ib_qp)
struct bnxt_re_dev *rdev = qp->rdev; struct bnxt_re_dev *rdev = qp->rdev;
int rc; int rc;
bnxt_qplib_del_flush_qp(&qp->qplib_qp);
rc = bnxt_qplib_destroy_qp(&rdev->qplib_res, &qp->qplib_qp); rc = bnxt_qplib_destroy_qp(&rdev->qplib_res, &qp->qplib_qp);
if (rc) { if (rc) {
dev_err(rdev_to_dev(rdev), "Failed to destroy HW QP"); dev_err(rdev_to_dev(rdev), "Failed to destroy HW QP");
...@@ -860,6 +801,7 @@ int bnxt_re_destroy_qp(struct ib_qp *ib_qp) ...@@ -860,6 +801,7 @@ int bnxt_re_destroy_qp(struct ib_qp *ib_qp)
return rc; return rc;
} }
bnxt_qplib_del_flush_qp(&qp->qplib_qp);
rc = bnxt_qplib_destroy_qp(&rdev->qplib_res, rc = bnxt_qplib_destroy_qp(&rdev->qplib_res,
&rdev->qp1_sqp->qplib_qp); &rdev->qp1_sqp->qplib_qp);
if (rc) { if (rc) {
...@@ -1404,6 +1346,21 @@ int bnxt_re_modify_qp(struct ib_qp *ib_qp, struct ib_qp_attr *qp_attr, ...@@ -1404,6 +1346,21 @@ int bnxt_re_modify_qp(struct ib_qp *ib_qp, struct ib_qp_attr *qp_attr,
} }
qp->qplib_qp.modify_flags |= CMDQ_MODIFY_QP_MODIFY_MASK_STATE; qp->qplib_qp.modify_flags |= CMDQ_MODIFY_QP_MODIFY_MASK_STATE;
qp->qplib_qp.state = __from_ib_qp_state(qp_attr->qp_state); qp->qplib_qp.state = __from_ib_qp_state(qp_attr->qp_state);
if (!qp->sumem &&
qp->qplib_qp.state == CMDQ_MODIFY_QP_NEW_STATE_ERR) {
dev_dbg(rdev_to_dev(rdev),
"Move QP = %p to flush list\n",
qp);
bnxt_qplib_add_flush_qp(&qp->qplib_qp);
}
if (!qp->sumem &&
qp->qplib_qp.state == CMDQ_MODIFY_QP_NEW_STATE_RESET) {
dev_dbg(rdev_to_dev(rdev),
"Move QP = %p out of flush list\n",
qp);
bnxt_qplib_del_flush_qp(&qp->qplib_qp);
}
} }
if (qp_attr_mask & IB_QP_EN_SQD_ASYNC_NOTIFY) { if (qp_attr_mask & IB_QP_EN_SQD_ASYNC_NOTIFY) {
qp->qplib_qp.modify_flags |= qp->qplib_qp.modify_flags |=
...@@ -2414,6 +2371,7 @@ struct ib_cq *bnxt_re_create_cq(struct ib_device *ibdev, ...@@ -2414,6 +2371,7 @@ struct ib_cq *bnxt_re_create_cq(struct ib_device *ibdev,
} }
cq->qplib_cq.max_wqe = entries; cq->qplib_cq.max_wqe = entries;
cq->qplib_cq.cnq_hw_ring_id = rdev->nq.ring_id; cq->qplib_cq.cnq_hw_ring_id = rdev->nq.ring_id;
cq->qplib_cq.nq = &rdev->nq;
rc = bnxt_qplib_create_cq(&rdev->qplib_res, &cq->qplib_cq); rc = bnxt_qplib_create_cq(&rdev->qplib_res, &cq->qplib_cq);
if (rc) { if (rc) {
...@@ -2921,6 +2879,10 @@ int bnxt_re_poll_cq(struct ib_cq *ib_cq, int num_entries, struct ib_wc *wc) ...@@ -2921,6 +2879,10 @@ int bnxt_re_poll_cq(struct ib_cq *ib_cq, int num_entries, struct ib_wc *wc)
sq->send_phantom = false; sq->send_phantom = false;
} }
} }
if (ncqe < budget)
ncqe += bnxt_qplib_process_flush_list(&cq->qplib_cq,
cqe + ncqe,
budget - ncqe);
if (!ncqe) if (!ncqe)
break; break;
......
...@@ -141,9 +141,6 @@ int bnxt_re_modify_device(struct ib_device *ibdev, ...@@ -141,9 +141,6 @@ int bnxt_re_modify_device(struct ib_device *ibdev,
struct ib_device_modify *device_modify); struct ib_device_modify *device_modify);
int bnxt_re_query_port(struct ib_device *ibdev, u8 port_num, int bnxt_re_query_port(struct ib_device *ibdev, u8 port_num,
struct ib_port_attr *port_attr); struct ib_port_attr *port_attr);
int bnxt_re_modify_port(struct ib_device *ibdev, u8 port_num,
int port_modify_mask,
struct ib_port_modify *port_modify);
int bnxt_re_get_port_immutable(struct ib_device *ibdev, u8 port_num, int bnxt_re_get_port_immutable(struct ib_device *ibdev, u8 port_num,
struct ib_port_immutable *immutable); struct ib_port_immutable *immutable);
int bnxt_re_query_pkey(struct ib_device *ibdev, u8 port_num, int bnxt_re_query_pkey(struct ib_device *ibdev, u8 port_num,
......
...@@ -70,7 +70,6 @@ static char version[] = ...@@ -70,7 +70,6 @@ static char version[] =
MODULE_AUTHOR("Eddie Wai <eddie.wai@broadcom.com>"); MODULE_AUTHOR("Eddie Wai <eddie.wai@broadcom.com>");
MODULE_DESCRIPTION(BNXT_RE_DESC " Driver"); MODULE_DESCRIPTION(BNXT_RE_DESC " Driver");
MODULE_LICENSE("Dual BSD/GPL"); MODULE_LICENSE("Dual BSD/GPL");
MODULE_VERSION(ROCE_DRV_MODULE_VERSION);
/* globals */ /* globals */
static struct list_head bnxt_re_dev_list = LIST_HEAD_INIT(bnxt_re_dev_list); static struct list_head bnxt_re_dev_list = LIST_HEAD_INIT(bnxt_re_dev_list);
...@@ -474,7 +473,6 @@ static int bnxt_re_register_ib(struct bnxt_re_dev *rdev) ...@@ -474,7 +473,6 @@ static int bnxt_re_register_ib(struct bnxt_re_dev *rdev)
ibdev->modify_device = bnxt_re_modify_device; ibdev->modify_device = bnxt_re_modify_device;
ibdev->query_port = bnxt_re_query_port; ibdev->query_port = bnxt_re_query_port;
ibdev->modify_port = bnxt_re_modify_port;
ibdev->get_port_immutable = bnxt_re_get_port_immutable; ibdev->get_port_immutable = bnxt_re_get_port_immutable;
ibdev->query_pkey = bnxt_re_query_pkey; ibdev->query_pkey = bnxt_re_query_pkey;
ibdev->query_gid = bnxt_re_query_gid; ibdev->query_gid = bnxt_re_query_gid;
...@@ -835,6 +833,42 @@ static void bnxt_re_dev_stop(struct bnxt_re_dev *rdev) ...@@ -835,6 +833,42 @@ static void bnxt_re_dev_stop(struct bnxt_re_dev *rdev)
mutex_unlock(&rdev->qp_lock); mutex_unlock(&rdev->qp_lock);
} }
static int bnxt_re_update_gid(struct bnxt_re_dev *rdev)
{
struct bnxt_qplib_sgid_tbl *sgid_tbl = &rdev->qplib_res.sgid_tbl;
struct bnxt_qplib_gid gid;
u16 gid_idx, index;
int rc = 0;
if (!test_bit(BNXT_RE_FLAG_IBDEV_REGISTERED, &rdev->flags))
return 0;
if (!sgid_tbl) {
dev_err(rdev_to_dev(rdev), "QPLIB: SGID table not allocated");
return -EINVAL;
}
for (index = 0; index < sgid_tbl->active; index++) {
gid_idx = sgid_tbl->hw_id[index];
if (!memcmp(&sgid_tbl->tbl[index], &bnxt_qplib_gid_zero,
sizeof(bnxt_qplib_gid_zero)))
continue;
/* need to modify the VLAN enable setting of non VLAN GID only
* as setting is done for VLAN GID while adding GID
*/
if (sgid_tbl->vlan[index])
continue;
memcpy(&gid, &sgid_tbl->tbl[index], sizeof(gid));
rc = bnxt_qplib_update_sgid(sgid_tbl, &gid, gid_idx,
rdev->qplib_res.netdev->dev_addr);
}
return rc;
}
static u32 bnxt_re_get_priority_mask(struct bnxt_re_dev *rdev) static u32 bnxt_re_get_priority_mask(struct bnxt_re_dev *rdev)
{ {
u32 prio_map = 0, tmp_map = 0; u32 prio_map = 0, tmp_map = 0;
...@@ -854,8 +888,6 @@ static u32 bnxt_re_get_priority_mask(struct bnxt_re_dev *rdev) ...@@ -854,8 +888,6 @@ static u32 bnxt_re_get_priority_mask(struct bnxt_re_dev *rdev)
tmp_map = dcb_ieee_getapp_mask(netdev, &app); tmp_map = dcb_ieee_getapp_mask(netdev, &app);
prio_map |= tmp_map; prio_map |= tmp_map;
if (!prio_map)
prio_map = -EFAULT;
return prio_map; return prio_map;
} }
...@@ -881,10 +913,7 @@ static int bnxt_re_setup_qos(struct bnxt_re_dev *rdev) ...@@ -881,10 +913,7 @@ static int bnxt_re_setup_qos(struct bnxt_re_dev *rdev)
int rc; int rc;
/* Get priority for roce */ /* Get priority for roce */
rc = bnxt_re_get_priority_mask(rdev); prio_map = bnxt_re_get_priority_mask(rdev);
if (rc < 0)
return rc;
prio_map = (u8)rc;
if (prio_map == rdev->cur_prio_map) if (prio_map == rdev->cur_prio_map)
return 0; return 0;
...@@ -906,6 +935,16 @@ static int bnxt_re_setup_qos(struct bnxt_re_dev *rdev) ...@@ -906,6 +935,16 @@ static int bnxt_re_setup_qos(struct bnxt_re_dev *rdev)
return rc; return rc;
} }
/* Actual priorities are not programmed as they are already
* done by L2 driver; just enable or disable priority vlan tagging
*/
if ((prio_map == 0 && rdev->qplib_res.prio) ||
(prio_map != 0 && !rdev->qplib_res.prio)) {
rdev->qplib_res.prio = prio_map ? true : false;
bnxt_re_update_gid(rdev);
}
return 0; return 0;
} }
...@@ -998,7 +1037,8 @@ static int bnxt_re_ib_reg(struct bnxt_re_dev *rdev) ...@@ -998,7 +1037,8 @@ static int bnxt_re_ib_reg(struct bnxt_re_dev *rdev)
/* Establish RCFW Communication Channel to initialize the context /* Establish RCFW Communication Channel to initialize the context
* memory for the function and all child VFs * memory for the function and all child VFs
*/ */
rc = bnxt_qplib_alloc_rcfw_channel(rdev->en_dev->pdev, &rdev->rcfw); rc = bnxt_qplib_alloc_rcfw_channel(rdev->en_dev->pdev, &rdev->rcfw,
BNXT_RE_MAX_QPC_COUNT);
if (rc) if (rc)
goto fail; goto fail;
......
...@@ -220,19 +220,20 @@ struct bnxt_qplib_q { ...@@ -220,19 +220,20 @@ struct bnxt_qplib_q {
u16 q_full_delta; u16 q_full_delta;
u16 max_sge; u16 max_sge;
u32 psn; u32 psn;
bool flush_in_progress;
bool condition; bool condition;
bool single; bool single;
bool send_phantom; bool send_phantom;
u32 phantom_wqe_cnt; u32 phantom_wqe_cnt;
u32 phantom_cqe_cnt; u32 phantom_cqe_cnt;
u32 next_cq_cons; u32 next_cq_cons;
bool flushed;
}; };
struct bnxt_qplib_qp { struct bnxt_qplib_qp {
struct bnxt_qplib_pd *pd; struct bnxt_qplib_pd *pd;
struct bnxt_qplib_dpi *dpi; struct bnxt_qplib_dpi *dpi;
u64 qp_handle; u64 qp_handle;
#define BNXT_QPLIB_QP_ID_INVALID 0xFFFFFFFF
u32 id; u32 id;
u8 type; u8 type;
u8 sig_type; u8 sig_type;
...@@ -296,6 +297,8 @@ struct bnxt_qplib_qp { ...@@ -296,6 +297,8 @@ struct bnxt_qplib_qp {
dma_addr_t sq_hdr_buf_map; dma_addr_t sq_hdr_buf_map;
void *rq_hdr_buf; void *rq_hdr_buf;
dma_addr_t rq_hdr_buf_map; dma_addr_t rq_hdr_buf_map;
struct list_head sq_flush;
struct list_head rq_flush;
}; };
#define BNXT_QPLIB_MAX_CQE_ENTRY_SIZE sizeof(struct cq_base) #define BNXT_QPLIB_MAX_CQE_ENTRY_SIZE sizeof(struct cq_base)
...@@ -351,6 +354,7 @@ struct bnxt_qplib_cq { ...@@ -351,6 +354,7 @@ struct bnxt_qplib_cq {
u16 period; u16 period;
struct bnxt_qplib_hwq hwq; struct bnxt_qplib_hwq hwq;
u32 cnq_hw_ring_id; u32 cnq_hw_ring_id;
struct bnxt_qplib_nq *nq;
bool resize_in_progress; bool resize_in_progress;
struct scatterlist *sghead; struct scatterlist *sghead;
u32 nmap; u32 nmap;
...@@ -360,6 +364,9 @@ struct bnxt_qplib_cq { ...@@ -360,6 +364,9 @@ struct bnxt_qplib_cq {
unsigned long flags; unsigned long flags;
#define CQ_FLAGS_RESIZE_IN_PROG 1 #define CQ_FLAGS_RESIZE_IN_PROG 1
wait_queue_head_t waitq; wait_queue_head_t waitq;
struct list_head sqf_head, rqf_head;
atomic_t arm_state;
spinlock_t compl_lock; /* synch CQ handlers */
}; };
#define BNXT_QPLIB_MAX_IRRQE_ENTRY_SIZE sizeof(struct xrrq_irrq) #define BNXT_QPLIB_MAX_IRRQE_ENTRY_SIZE sizeof(struct xrrq_irrq)
...@@ -417,6 +424,13 @@ struct bnxt_qplib_nq { ...@@ -417,6 +424,13 @@ struct bnxt_qplib_nq {
(struct bnxt_qplib_nq *nq, (struct bnxt_qplib_nq *nq,
void *srq, void *srq,
u8 event); u8 event);
struct workqueue_struct *cqn_wq;
};
struct bnxt_qplib_nq_work {
struct work_struct work;
struct bnxt_qplib_nq *nq;
struct bnxt_qplib_cq *cq;
}; };
void bnxt_qplib_disable_nq(struct bnxt_qplib_nq *nq); void bnxt_qplib_disable_nq(struct bnxt_qplib_nq *nq);
...@@ -453,4 +467,13 @@ bool bnxt_qplib_is_cq_empty(struct bnxt_qplib_cq *cq); ...@@ -453,4 +467,13 @@ bool bnxt_qplib_is_cq_empty(struct bnxt_qplib_cq *cq);
void bnxt_qplib_req_notify_cq(struct bnxt_qplib_cq *cq, u32 arm_type); void bnxt_qplib_req_notify_cq(struct bnxt_qplib_cq *cq, u32 arm_type);
void bnxt_qplib_free_nq(struct bnxt_qplib_nq *nq); void bnxt_qplib_free_nq(struct bnxt_qplib_nq *nq);
int bnxt_qplib_alloc_nq(struct pci_dev *pdev, struct bnxt_qplib_nq *nq); int bnxt_qplib_alloc_nq(struct pci_dev *pdev, struct bnxt_qplib_nq *nq);
void bnxt_qplib_add_flush_qp(struct bnxt_qplib_qp *qp);
void bnxt_qplib_del_flush_qp(struct bnxt_qplib_qp *qp);
void bnxt_qplib_acquire_cq_locks(struct bnxt_qplib_qp *qp,
unsigned long *flags);
void bnxt_qplib_release_cq_locks(struct bnxt_qplib_qp *qp,
unsigned long *flags);
int bnxt_qplib_process_flush_list(struct bnxt_qplib_cq *cq,
struct bnxt_qplib_cqe *cqe,
int num_cqes);
#endif /* __BNXT_QPLIB_FP_H__ */ #endif /* __BNXT_QPLIB_FP_H__ */
...@@ -44,6 +44,9 @@ ...@@ -44,6 +44,9 @@
#include "roce_hsi.h" #include "roce_hsi.h"
#include "qplib_res.h" #include "qplib_res.h"
#include "qplib_rcfw.h" #include "qplib_rcfw.h"
#include "qplib_sp.h"
#include "qplib_fp.h"
static void bnxt_qplib_service_creq(unsigned long data); static void bnxt_qplib_service_creq(unsigned long data);
/* Hardware communication channel */ /* Hardware communication channel */
...@@ -279,16 +282,29 @@ static int bnxt_qplib_process_qp_event(struct bnxt_qplib_rcfw *rcfw, ...@@ -279,16 +282,29 @@ static int bnxt_qplib_process_qp_event(struct bnxt_qplib_rcfw *rcfw,
struct creq_qp_event *qp_event) struct creq_qp_event *qp_event)
{ {
struct bnxt_qplib_hwq *cmdq = &rcfw->cmdq; struct bnxt_qplib_hwq *cmdq = &rcfw->cmdq;
struct creq_qp_error_notification *err_event;
struct bnxt_qplib_crsq *crsqe; struct bnxt_qplib_crsq *crsqe;
unsigned long flags; unsigned long flags;
struct bnxt_qplib_qp *qp;
u16 cbit, blocked = 0; u16 cbit, blocked = 0;
u16 cookie; u16 cookie;
__le16 mcookie; __le16 mcookie;
u32 qp_id;
switch (qp_event->event) { switch (qp_event->event) {
case CREQ_QP_EVENT_EVENT_QP_ERROR_NOTIFICATION: case CREQ_QP_EVENT_EVENT_QP_ERROR_NOTIFICATION:
err_event = (struct creq_qp_error_notification *)qp_event;
qp_id = le32_to_cpu(err_event->xid);
qp = rcfw->qp_tbl[qp_id].qp_handle;
dev_dbg(&rcfw->pdev->dev, dev_dbg(&rcfw->pdev->dev,
"QPLIB: Received QP error notification"); "QPLIB: Received QP error notification");
dev_dbg(&rcfw->pdev->dev,
"QPLIB: qpid 0x%x, req_err=0x%x, resp_err=0x%x\n",
qp_id, err_event->req_err_state_reason,
err_event->res_err_state_reason);
bnxt_qplib_acquire_cq_locks(qp, &flags);
bnxt_qplib_mark_qp_error(qp);
bnxt_qplib_release_cq_locks(qp, &flags);
break; break;
default: default:
/* Command Response */ /* Command Response */
...@@ -507,6 +523,7 @@ int bnxt_qplib_init_rcfw(struct bnxt_qplib_rcfw *rcfw, ...@@ -507,6 +523,7 @@ int bnxt_qplib_init_rcfw(struct bnxt_qplib_rcfw *rcfw,
void bnxt_qplib_free_rcfw_channel(struct bnxt_qplib_rcfw *rcfw) void bnxt_qplib_free_rcfw_channel(struct bnxt_qplib_rcfw *rcfw)
{ {
kfree(rcfw->qp_tbl);
kfree(rcfw->crsqe_tbl); kfree(rcfw->crsqe_tbl);
bnxt_qplib_free_hwq(rcfw->pdev, &rcfw->cmdq); bnxt_qplib_free_hwq(rcfw->pdev, &rcfw->cmdq);
bnxt_qplib_free_hwq(rcfw->pdev, &rcfw->creq); bnxt_qplib_free_hwq(rcfw->pdev, &rcfw->creq);
...@@ -514,7 +531,8 @@ void bnxt_qplib_free_rcfw_channel(struct bnxt_qplib_rcfw *rcfw) ...@@ -514,7 +531,8 @@ void bnxt_qplib_free_rcfw_channel(struct bnxt_qplib_rcfw *rcfw)
} }
int bnxt_qplib_alloc_rcfw_channel(struct pci_dev *pdev, int bnxt_qplib_alloc_rcfw_channel(struct pci_dev *pdev,
struct bnxt_qplib_rcfw *rcfw) struct bnxt_qplib_rcfw *rcfw,
int qp_tbl_sz)
{ {
rcfw->pdev = pdev; rcfw->pdev = pdev;
rcfw->creq.max_elements = BNXT_QPLIB_CREQE_MAX_CNT; rcfw->creq.max_elements = BNXT_QPLIB_CREQE_MAX_CNT;
...@@ -541,6 +559,12 @@ int bnxt_qplib_alloc_rcfw_channel(struct pci_dev *pdev, ...@@ -541,6 +559,12 @@ int bnxt_qplib_alloc_rcfw_channel(struct pci_dev *pdev,
if (!rcfw->crsqe_tbl) if (!rcfw->crsqe_tbl)
goto fail; goto fail;
rcfw->qp_tbl_size = qp_tbl_sz;
rcfw->qp_tbl = kcalloc(qp_tbl_sz, sizeof(struct bnxt_qplib_qp_node),
GFP_KERNEL);
if (!rcfw->qp_tbl)
goto fail;
return 0; return 0;
fail: fail:
......
...@@ -148,6 +148,11 @@ struct bnxt_qplib_rcfw_sbuf { ...@@ -148,6 +148,11 @@ struct bnxt_qplib_rcfw_sbuf {
u32 size; u32 size;
}; };
struct bnxt_qplib_qp_node {
u32 qp_id; /* QP id */
void *qp_handle; /* ptr to qplib_qp */
};
/* RCFW Communication Channels */ /* RCFW Communication Channels */
struct bnxt_qplib_rcfw { struct bnxt_qplib_rcfw {
struct pci_dev *pdev; struct pci_dev *pdev;
...@@ -181,11 +186,13 @@ struct bnxt_qplib_rcfw { ...@@ -181,11 +186,13 @@ struct bnxt_qplib_rcfw {
/* Actual Cmd and Resp Queues */ /* Actual Cmd and Resp Queues */
struct bnxt_qplib_hwq cmdq; struct bnxt_qplib_hwq cmdq;
struct bnxt_qplib_crsq *crsqe_tbl; struct bnxt_qplib_crsq *crsqe_tbl;
int qp_tbl_size;
struct bnxt_qplib_qp_node *qp_tbl;
}; };
void bnxt_qplib_free_rcfw_channel(struct bnxt_qplib_rcfw *rcfw); void bnxt_qplib_free_rcfw_channel(struct bnxt_qplib_rcfw *rcfw);
int bnxt_qplib_alloc_rcfw_channel(struct pci_dev *pdev, int bnxt_qplib_alloc_rcfw_channel(struct pci_dev *pdev,
struct bnxt_qplib_rcfw *rcfw); struct bnxt_qplib_rcfw *rcfw, int qp_tbl_sz);
void bnxt_qplib_disable_rcfw_channel(struct bnxt_qplib_rcfw *rcfw); void bnxt_qplib_disable_rcfw_channel(struct bnxt_qplib_rcfw *rcfw);
int bnxt_qplib_enable_rcfw_channel(struct pci_dev *pdev, int bnxt_qplib_enable_rcfw_channel(struct pci_dev *pdev,
struct bnxt_qplib_rcfw *rcfw, struct bnxt_qplib_rcfw *rcfw,
...@@ -207,4 +214,5 @@ int bnxt_qplib_rcfw_send_message(struct bnxt_qplib_rcfw *rcfw, ...@@ -207,4 +214,5 @@ int bnxt_qplib_rcfw_send_message(struct bnxt_qplib_rcfw *rcfw,
int bnxt_qplib_deinit_rcfw(struct bnxt_qplib_rcfw *rcfw); int bnxt_qplib_deinit_rcfw(struct bnxt_qplib_rcfw *rcfw);
int bnxt_qplib_init_rcfw(struct bnxt_qplib_rcfw *rcfw, int bnxt_qplib_init_rcfw(struct bnxt_qplib_rcfw *rcfw,
struct bnxt_qplib_ctx *ctx, int is_virtfn); struct bnxt_qplib_ctx *ctx, int is_virtfn);
void bnxt_qplib_mark_qp_error(void *qp_handle);
#endif /* __BNXT_QPLIB_RCFW_H__ */ #endif /* __BNXT_QPLIB_RCFW_H__ */
...@@ -468,9 +468,11 @@ static void bnxt_qplib_free_sgid_tbl(struct bnxt_qplib_res *res, ...@@ -468,9 +468,11 @@ static void bnxt_qplib_free_sgid_tbl(struct bnxt_qplib_res *res,
kfree(sgid_tbl->tbl); kfree(sgid_tbl->tbl);
kfree(sgid_tbl->hw_id); kfree(sgid_tbl->hw_id);
kfree(sgid_tbl->ctx); kfree(sgid_tbl->ctx);
kfree(sgid_tbl->vlan);
sgid_tbl->tbl = NULL; sgid_tbl->tbl = NULL;
sgid_tbl->hw_id = NULL; sgid_tbl->hw_id = NULL;
sgid_tbl->ctx = NULL; sgid_tbl->ctx = NULL;
sgid_tbl->vlan = NULL;
sgid_tbl->max = 0; sgid_tbl->max = 0;
sgid_tbl->active = 0; sgid_tbl->active = 0;
} }
...@@ -491,8 +493,15 @@ static int bnxt_qplib_alloc_sgid_tbl(struct bnxt_qplib_res *res, ...@@ -491,8 +493,15 @@ static int bnxt_qplib_alloc_sgid_tbl(struct bnxt_qplib_res *res,
if (!sgid_tbl->ctx) if (!sgid_tbl->ctx)
goto out_free2; goto out_free2;
sgid_tbl->vlan = kcalloc(max, sizeof(u8), GFP_KERNEL);
if (!sgid_tbl->vlan)
goto out_free3;
sgid_tbl->max = max; sgid_tbl->max = max;
return 0; return 0;
out_free3:
kfree(sgid_tbl->ctx);
sgid_tbl->ctx = NULL;
out_free2: out_free2:
kfree(sgid_tbl->hw_id); kfree(sgid_tbl->hw_id);
sgid_tbl->hw_id = NULL; sgid_tbl->hw_id = NULL;
...@@ -514,6 +523,7 @@ static void bnxt_qplib_cleanup_sgid_tbl(struct bnxt_qplib_res *res, ...@@ -514,6 +523,7 @@ static void bnxt_qplib_cleanup_sgid_tbl(struct bnxt_qplib_res *res,
} }
memset(sgid_tbl->tbl, 0, sizeof(struct bnxt_qplib_gid) * sgid_tbl->max); memset(sgid_tbl->tbl, 0, sizeof(struct bnxt_qplib_gid) * sgid_tbl->max);
memset(sgid_tbl->hw_id, -1, sizeof(u16) * sgid_tbl->max); memset(sgid_tbl->hw_id, -1, sizeof(u16) * sgid_tbl->max);
memset(sgid_tbl->vlan, 0, sizeof(u8) * sgid_tbl->max);
sgid_tbl->active = 0; sgid_tbl->active = 0;
} }
......
...@@ -116,6 +116,7 @@ struct bnxt_qplib_sgid_tbl { ...@@ -116,6 +116,7 @@ struct bnxt_qplib_sgid_tbl {
u16 max; u16 max;
u16 active; u16 active;
void *ctx; void *ctx;
u8 *vlan;
}; };
struct bnxt_qplib_pkey_tbl { struct bnxt_qplib_pkey_tbl {
...@@ -188,6 +189,7 @@ struct bnxt_qplib_res { ...@@ -188,6 +189,7 @@ struct bnxt_qplib_res {
struct bnxt_qplib_sgid_tbl sgid_tbl; struct bnxt_qplib_sgid_tbl sgid_tbl;
struct bnxt_qplib_pkey_tbl pkey_tbl; struct bnxt_qplib_pkey_tbl pkey_tbl;
struct bnxt_qplib_dpi_tbl dpi_tbl; struct bnxt_qplib_dpi_tbl dpi_tbl;
bool prio;
}; };
#define to_bnxt_qplib(ptr, type, member) \ #define to_bnxt_qplib(ptr, type, member) \
......
...@@ -213,6 +213,7 @@ int bnxt_qplib_del_sgid(struct bnxt_qplib_sgid_tbl *sgid_tbl, ...@@ -213,6 +213,7 @@ int bnxt_qplib_del_sgid(struct bnxt_qplib_sgid_tbl *sgid_tbl,
} }
memcpy(&sgid_tbl->tbl[index], &bnxt_qplib_gid_zero, memcpy(&sgid_tbl->tbl[index], &bnxt_qplib_gid_zero,
sizeof(bnxt_qplib_gid_zero)); sizeof(bnxt_qplib_gid_zero));
sgid_tbl->vlan[index] = 0;
sgid_tbl->active--; sgid_tbl->active--;
dev_dbg(&res->pdev->dev, dev_dbg(&res->pdev->dev,
"QPLIB: SGID deleted hw_id[0x%x] = 0x%x active = 0x%x", "QPLIB: SGID deleted hw_id[0x%x] = 0x%x active = 0x%x",
...@@ -265,28 +266,32 @@ int bnxt_qplib_add_sgid(struct bnxt_qplib_sgid_tbl *sgid_tbl, ...@@ -265,28 +266,32 @@ int bnxt_qplib_add_sgid(struct bnxt_qplib_sgid_tbl *sgid_tbl,
struct cmdq_add_gid req; struct cmdq_add_gid req;
struct creq_add_gid_resp resp; struct creq_add_gid_resp resp;
u16 cmd_flags = 0; u16 cmd_flags = 0;
u32 temp32[4];
u16 temp16[3];
int rc; int rc;
RCFW_CMD_PREP(req, ADD_GID, cmd_flags); RCFW_CMD_PREP(req, ADD_GID, cmd_flags);
memcpy(temp32, gid->data, sizeof(struct bnxt_qplib_gid)); req.gid[0] = cpu_to_be32(((u32 *)gid->data)[3]);
req.gid[0] = cpu_to_be32(temp32[3]); req.gid[1] = cpu_to_be32(((u32 *)gid->data)[2]);
req.gid[1] = cpu_to_be32(temp32[2]); req.gid[2] = cpu_to_be32(((u32 *)gid->data)[1]);
req.gid[2] = cpu_to_be32(temp32[1]); req.gid[3] = cpu_to_be32(((u32 *)gid->data)[0]);
req.gid[3] = cpu_to_be32(temp32[0]); /*
if (vlan_id != 0xFFFF) * driver should ensure that all RoCE traffic is always VLAN
req.vlan = cpu_to_le16((vlan_id & * tagged if RoCE traffic is running on non-zero VLAN ID or
CMDQ_ADD_GID_VLAN_VLAN_ID_MASK) | * RoCE traffic is running on non-zero Priority.
CMDQ_ADD_GID_VLAN_TPID_TPID_8100 | */
CMDQ_ADD_GID_VLAN_VLAN_EN); if ((vlan_id != 0xFFFF) || res->prio) {
if (vlan_id != 0xFFFF)
req.vlan = cpu_to_le16
(vlan_id & CMDQ_ADD_GID_VLAN_VLAN_ID_MASK);
req.vlan |= cpu_to_le16
(CMDQ_ADD_GID_VLAN_TPID_TPID_8100 |
CMDQ_ADD_GID_VLAN_VLAN_EN);
}
/* MAC in network format */ /* MAC in network format */
memcpy(temp16, smac, 6); req.src_mac[0] = cpu_to_be16(((u16 *)smac)[0]);
req.src_mac[0] = cpu_to_be16(temp16[0]); req.src_mac[1] = cpu_to_be16(((u16 *)smac)[1]);
req.src_mac[1] = cpu_to_be16(temp16[1]); req.src_mac[2] = cpu_to_be16(((u16 *)smac)[2]);
req.src_mac[2] = cpu_to_be16(temp16[2]);
rc = bnxt_qplib_rcfw_send_message(rcfw, (void *)&req, rc = bnxt_qplib_rcfw_send_message(rcfw, (void *)&req,
(void *)&resp, NULL, 0); (void *)&resp, NULL, 0);
...@@ -297,6 +302,9 @@ int bnxt_qplib_add_sgid(struct bnxt_qplib_sgid_tbl *sgid_tbl, ...@@ -297,6 +302,9 @@ int bnxt_qplib_add_sgid(struct bnxt_qplib_sgid_tbl *sgid_tbl,
/* Add GID to the sgid_tbl */ /* Add GID to the sgid_tbl */
memcpy(&sgid_tbl->tbl[free_idx], gid, sizeof(*gid)); memcpy(&sgid_tbl->tbl[free_idx], gid, sizeof(*gid));
sgid_tbl->active++; sgid_tbl->active++;
if (vlan_id != 0xFFFF)
sgid_tbl->vlan[free_idx] = 1;
dev_dbg(&res->pdev->dev, dev_dbg(&res->pdev->dev,
"QPLIB: SGID added hw_id[0x%x] = 0x%x active = 0x%x", "QPLIB: SGID added hw_id[0x%x] = 0x%x active = 0x%x",
free_idx, sgid_tbl->hw_id[free_idx], sgid_tbl->active); free_idx, sgid_tbl->hw_id[free_idx], sgid_tbl->active);
...@@ -306,6 +314,43 @@ int bnxt_qplib_add_sgid(struct bnxt_qplib_sgid_tbl *sgid_tbl, ...@@ -306,6 +314,43 @@ int bnxt_qplib_add_sgid(struct bnxt_qplib_sgid_tbl *sgid_tbl,
return 0; return 0;
} }
int bnxt_qplib_update_sgid(struct bnxt_qplib_sgid_tbl *sgid_tbl,
struct bnxt_qplib_gid *gid, u16 gid_idx,
u8 *smac)
{
struct bnxt_qplib_res *res = to_bnxt_qplib(sgid_tbl,
struct bnxt_qplib_res,
sgid_tbl);
struct bnxt_qplib_rcfw *rcfw = res->rcfw;
struct creq_modify_gid_resp resp;
struct cmdq_modify_gid req;
int rc;
u16 cmd_flags = 0;
RCFW_CMD_PREP(req, MODIFY_GID, cmd_flags);
req.gid[0] = cpu_to_be32(((u32 *)gid->data)[3]);
req.gid[1] = cpu_to_be32(((u32 *)gid->data)[2]);
req.gid[2] = cpu_to_be32(((u32 *)gid->data)[1]);
req.gid[3] = cpu_to_be32(((u32 *)gid->data)[0]);
if (res->prio) {
req.vlan |= cpu_to_le16
(CMDQ_ADD_GID_VLAN_TPID_TPID_8100 |
CMDQ_ADD_GID_VLAN_VLAN_EN);
}
/* MAC in network format */
req.src_mac[0] = cpu_to_be16(((u16 *)smac)[0]);
req.src_mac[1] = cpu_to_be16(((u16 *)smac)[1]);
req.src_mac[2] = cpu_to_be16(((u16 *)smac)[2]);
req.gid_index = cpu_to_le16(gid_idx);
rc = bnxt_qplib_rcfw_send_message(rcfw, (void *)&req,
(void *)&resp, NULL, 0);
return rc;
}
/* pkeys */ /* pkeys */
int bnxt_qplib_get_pkey(struct bnxt_qplib_res *res, int bnxt_qplib_get_pkey(struct bnxt_qplib_res *res,
struct bnxt_qplib_pkey_tbl *pkey_tbl, u16 index, struct bnxt_qplib_pkey_tbl *pkey_tbl, u16 index,
......
...@@ -135,6 +135,8 @@ int bnxt_qplib_del_sgid(struct bnxt_qplib_sgid_tbl *sgid_tbl, ...@@ -135,6 +135,8 @@ int bnxt_qplib_del_sgid(struct bnxt_qplib_sgid_tbl *sgid_tbl,
int bnxt_qplib_add_sgid(struct bnxt_qplib_sgid_tbl *sgid_tbl, int bnxt_qplib_add_sgid(struct bnxt_qplib_sgid_tbl *sgid_tbl,
struct bnxt_qplib_gid *gid, u8 *mac, u16 vlan_id, struct bnxt_qplib_gid *gid, u8 *mac, u16 vlan_id,
bool update, u32 *index); bool update, u32 *index);
int bnxt_qplib_update_sgid(struct bnxt_qplib_sgid_tbl *sgid_tbl,
struct bnxt_qplib_gid *gid, u16 gid_idx, u8 *smac);
int bnxt_qplib_get_pkey(struct bnxt_qplib_res *res, int bnxt_qplib_get_pkey(struct bnxt_qplib_res *res,
struct bnxt_qplib_pkey_tbl *pkey_tbl, u16 index, struct bnxt_qplib_pkey_tbl *pkey_tbl, u16 index,
u16 *pkey); u16 *pkey);
......
...@@ -1473,8 +1473,8 @@ struct cmdq_modify_gid { ...@@ -1473,8 +1473,8 @@ struct cmdq_modify_gid {
u8 resp_size; u8 resp_size;
u8 reserved8; u8 reserved8;
__le64 resp_addr; __le64 resp_addr;
__le32 gid[4]; __be32 gid[4];
__le16 src_mac[3]; __be16 src_mac[3];
__le16 vlan; __le16 vlan;
#define CMDQ_MODIFY_GID_VLAN_VLAN_ID_MASK 0xfffUL #define CMDQ_MODIFY_GID_VLAN_VLAN_ID_MASK 0xfffUL
#define CMDQ_MODIFY_GID_VLAN_VLAN_ID_SFT 0 #define CMDQ_MODIFY_GID_VLAN_VLAN_ID_SFT 0
......
...@@ -45,7 +45,6 @@ ...@@ -45,7 +45,6 @@
MODULE_AUTHOR("Boyd Faulkner, Steve Wise"); MODULE_AUTHOR("Boyd Faulkner, Steve Wise");
MODULE_DESCRIPTION("Chelsio T3 RDMA Driver"); MODULE_DESCRIPTION("Chelsio T3 RDMA Driver");
MODULE_LICENSE("Dual BSD/GPL"); MODULE_LICENSE("Dual BSD/GPL");
MODULE_VERSION(DRV_VERSION);
static void open_rnic_dev(struct t3cdev *); static void open_rnic_dev(struct t3cdev *);
static void close_rnic_dev(struct t3cdev *); static void close_rnic_dev(struct t3cdev *);
......
...@@ -1336,8 +1336,7 @@ static int iwch_port_immutable(struct ib_device *ibdev, u8 port_num, ...@@ -1336,8 +1336,7 @@ static int iwch_port_immutable(struct ib_device *ibdev, u8 port_num,
return 0; return 0;
} }
static void get_dev_fw_ver_str(struct ib_device *ibdev, char *str, static void get_dev_fw_ver_str(struct ib_device *ibdev, char *str)
size_t str_len)
{ {
struct iwch_dev *iwch_dev = to_iwch_dev(ibdev); struct iwch_dev *iwch_dev = to_iwch_dev(ibdev);
struct ethtool_drvinfo info; struct ethtool_drvinfo info;
...@@ -1345,7 +1344,7 @@ static void get_dev_fw_ver_str(struct ib_device *ibdev, char *str, ...@@ -1345,7 +1344,7 @@ static void get_dev_fw_ver_str(struct ib_device *ibdev, char *str,
pr_debug("%s dev 0x%p\n", __func__, iwch_dev); pr_debug("%s dev 0x%p\n", __func__, iwch_dev);
lldev->ethtool_ops->get_drvinfo(lldev, &info); lldev->ethtool_ops->get_drvinfo(lldev, &info);
snprintf(str, str_len, "%s", info.fw_version); snprintf(str, IB_FW_VERSION_NAME_MAX, "%s", info.fw_version);
} }
int iwch_register_device(struct iwch_dev *dev) int iwch_register_device(struct iwch_dev *dev)
......
...@@ -44,7 +44,6 @@ ...@@ -44,7 +44,6 @@
MODULE_AUTHOR("Steve Wise"); MODULE_AUTHOR("Steve Wise");
MODULE_DESCRIPTION("Chelsio T4/T5 RDMA Driver"); MODULE_DESCRIPTION("Chelsio T4/T5 RDMA Driver");
MODULE_LICENSE("Dual BSD/GPL"); MODULE_LICENSE("Dual BSD/GPL");
MODULE_VERSION(DRV_VERSION);
static int allow_db_fc_on_t5; static int allow_db_fc_on_t5;
module_param(allow_db_fc_on_t5, int, 0644); module_param(allow_db_fc_on_t5, int, 0644);
......
...@@ -517,14 +517,13 @@ static int c4iw_port_immutable(struct ib_device *ibdev, u8 port_num, ...@@ -517,14 +517,13 @@ static int c4iw_port_immutable(struct ib_device *ibdev, u8 port_num,
return 0; return 0;
} }
static void get_dev_fw_str(struct ib_device *dev, char *str, static void get_dev_fw_str(struct ib_device *dev, char *str)
size_t str_len)
{ {
struct c4iw_dev *c4iw_dev = container_of(dev, struct c4iw_dev, struct c4iw_dev *c4iw_dev = container_of(dev, struct c4iw_dev,
ibdev); ibdev);
pr_debug("%s dev 0x%p\n", __func__, dev); pr_debug("%s dev 0x%p\n", __func__, dev);
snprintf(str, str_len, "%u.%u.%u.%u", snprintf(str, IB_FW_VERSION_NAME_MAX, "%u.%u.%u.%u",
FW_HDR_FW_VER_MAJOR_G(c4iw_dev->rdev.lldi.fw_vers), FW_HDR_FW_VER_MAJOR_G(c4iw_dev->rdev.lldi.fw_vers),
FW_HDR_FW_VER_MINOR_G(c4iw_dev->rdev.lldi.fw_vers), FW_HDR_FW_VER_MINOR_G(c4iw_dev->rdev.lldi.fw_vers),
FW_HDR_FW_VER_MICRO_G(c4iw_dev->rdev.lldi.fw_vers), FW_HDR_FW_VER_MICRO_G(c4iw_dev->rdev.lldi.fw_vers),
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
obj-$(CONFIG_INFINIBAND_HFI1) += hfi1.o obj-$(CONFIG_INFINIBAND_HFI1) += hfi1.o
hfi1-y := affinity.o chip.o device.o driver.o efivar.o \ hfi1-y := affinity.o chip.o device.o driver.o efivar.o \
eprom.o file_ops.o firmware.o \ eprom.o exp_rcv.o file_ops.o firmware.o \
init.o intr.o mad.o mmu_rb.o pcie.o pio.o pio_copy.o platform.o \ init.o intr.o mad.o mmu_rb.o pcie.o pio.o pio_copy.o platform.o \
qp.o qsfp.o rc.o ruc.o sdma.o sysfs.o trace.o \ qp.o qsfp.o rc.o ruc.o sdma.o sysfs.o trace.o \
uc.o ud.o user_exp_rcv.o user_pages.o user_sdma.o verbs.o \ uc.o ud.o user_exp_rcv.o user_pages.o user_sdma.o verbs.o \
......
/* /*
* Copyright(c) 2015, 2016 Intel Corporation. * Copyright(c) 2015 - 2017 Intel Corporation.
* *
* This file is provided under a dual BSD/GPLv2 license. When using or * This file is provided under a dual BSD/GPLv2 license. When using or
* redistributing this file, you may do so under either license. * redistributing this file, you may do so under either license.
...@@ -335,10 +335,10 @@ static void hfi1_update_sdma_affinity(struct hfi1_msix_entry *msix, int cpu) ...@@ -335,10 +335,10 @@ static void hfi1_update_sdma_affinity(struct hfi1_msix_entry *msix, int cpu)
sde->cpu = cpu; sde->cpu = cpu;
cpumask_clear(&msix->mask); cpumask_clear(&msix->mask);
cpumask_set_cpu(cpu, &msix->mask); cpumask_set_cpu(cpu, &msix->mask);
dd_dev_dbg(dd, "IRQ vector: %u, type %s engine %u -> cpu: %d\n", dd_dev_dbg(dd, "IRQ: %u, type %s engine %u -> cpu: %d\n",
msix->msix.vector, irq_type_names[msix->type], msix->irq, irq_type_names[msix->type],
sde->this_idx, cpu); sde->this_idx, cpu);
irq_set_affinity_hint(msix->msix.vector, &msix->mask); irq_set_affinity_hint(msix->irq, &msix->mask);
/* /*
* Set the new cpu in the hfi1_affinity_node and clean * Set the new cpu in the hfi1_affinity_node and clean
...@@ -387,7 +387,7 @@ static void hfi1_setup_sdma_notifier(struct hfi1_msix_entry *msix) ...@@ -387,7 +387,7 @@ static void hfi1_setup_sdma_notifier(struct hfi1_msix_entry *msix)
{ {
struct irq_affinity_notify *notify = &msix->notify; struct irq_affinity_notify *notify = &msix->notify;
notify->irq = msix->msix.vector; notify->irq = msix->irq;
notify->notify = hfi1_irq_notifier_notify; notify->notify = hfi1_irq_notifier_notify;
notify->release = hfi1_irq_notifier_release; notify->release = hfi1_irq_notifier_release;
...@@ -472,10 +472,10 @@ static int get_irq_affinity(struct hfi1_devdata *dd, ...@@ -472,10 +472,10 @@ static int get_irq_affinity(struct hfi1_devdata *dd,
} }
cpumask_set_cpu(cpu, &msix->mask); cpumask_set_cpu(cpu, &msix->mask);
dd_dev_info(dd, "IRQ vector: %u, type %s %s -> cpu: %d\n", dd_dev_info(dd, "IRQ: %u, type %s %s -> cpu: %d\n",
msix->msix.vector, irq_type_names[msix->type], msix->irq, irq_type_names[msix->type],
extra, cpu); extra, cpu);
irq_set_affinity_hint(msix->msix.vector, &msix->mask); irq_set_affinity_hint(msix->irq, &msix->mask);
if (msix->type == IRQ_SDMA) { if (msix->type == IRQ_SDMA) {
sde->cpu = cpu; sde->cpu = cpu;
...@@ -533,7 +533,7 @@ void hfi1_put_irq_affinity(struct hfi1_devdata *dd, ...@@ -533,7 +533,7 @@ void hfi1_put_irq_affinity(struct hfi1_devdata *dd,
} }
} }
irq_set_affinity_hint(msix->msix.vector, NULL); irq_set_affinity_hint(msix->irq, NULL);
cpumask_clear(&msix->mask); cpumask_clear(&msix->mask);
mutex_unlock(&node_affinity.lock); mutex_unlock(&node_affinity.lock);
} }
......
/* /*
* Copyright(c) 2015, 2016 Intel Corporation. * Copyright(c) 2015 - 2017 Intel Corporation.
* *
* This file is provided under a dual BSD/GPLv2 license. When using or * This file is provided under a dual BSD/GPLv2 license. When using or
* redistributing this file, you may do so under either license. * redistributing this file, you may do so under either license.
...@@ -75,24 +75,26 @@ struct hfi1_msix_entry; ...@@ -75,24 +75,26 @@ struct hfi1_msix_entry;
/* Initialize non-HT cpu cores mask */ /* Initialize non-HT cpu cores mask */
void init_real_cpu_mask(void); void init_real_cpu_mask(void);
/* Initialize driver affinity data */ /* Initialize driver affinity data */
int hfi1_dev_affinity_init(struct hfi1_devdata *); int hfi1_dev_affinity_init(struct hfi1_devdata *dd);
/* /*
* Set IRQ affinity to a CPU. The function will determine the * Set IRQ affinity to a CPU. The function will determine the
* CPU and set the affinity to it. * CPU and set the affinity to it.
*/ */
int hfi1_get_irq_affinity(struct hfi1_devdata *, struct hfi1_msix_entry *); int hfi1_get_irq_affinity(struct hfi1_devdata *dd,
struct hfi1_msix_entry *msix);
/* /*
* Remove the IRQ's CPU affinity. This function also updates * Remove the IRQ's CPU affinity. This function also updates
* any internal CPU tracking data * any internal CPU tracking data
*/ */
void hfi1_put_irq_affinity(struct hfi1_devdata *, struct hfi1_msix_entry *); void hfi1_put_irq_affinity(struct hfi1_devdata *dd,
struct hfi1_msix_entry *msix);
/* /*
* Determine a CPU affinity for a user process, if the process does not * Determine a CPU affinity for a user process, if the process does not
* have an affinity set yet. * have an affinity set yet.
*/ */
int hfi1_get_proc_affinity(int); int hfi1_get_proc_affinity(int node);
/* Release a CPU used by a user process. */ /* Release a CPU used by a user process. */
void hfi1_put_proc_affinity(int); void hfi1_put_proc_affinity(int cpu);
struct hfi1_affinity_node { struct hfi1_affinity_node {
int node; int node;
......
...@@ -237,7 +237,7 @@ static inline void aspm_disable_all(struct hfi1_devdata *dd) ...@@ -237,7 +237,7 @@ static inline void aspm_disable_all(struct hfi1_devdata *dd)
{ {
struct hfi1_ctxtdata *rcd; struct hfi1_ctxtdata *rcd;
unsigned long flags; unsigned long flags;
unsigned i; u16 i;
for (i = 0; i < dd->first_dyn_alloc_ctxt; i++) { for (i = 0; i < dd->first_dyn_alloc_ctxt; i++) {
rcd = dd->rcd[i]; rcd = dd->rcd[i];
...@@ -256,7 +256,7 @@ static inline void aspm_enable_all(struct hfi1_devdata *dd) ...@@ -256,7 +256,7 @@ static inline void aspm_enable_all(struct hfi1_devdata *dd)
{ {
struct hfi1_ctxtdata *rcd; struct hfi1_ctxtdata *rcd;
unsigned long flags; unsigned long flags;
unsigned i; u16 i;
aspm_enable(dd); aspm_enable(dd);
...@@ -284,7 +284,7 @@ static inline void aspm_ctx_init(struct hfi1_ctxtdata *rcd) ...@@ -284,7 +284,7 @@ static inline void aspm_ctx_init(struct hfi1_ctxtdata *rcd)
static inline void aspm_init(struct hfi1_devdata *dd) static inline void aspm_init(struct hfi1_devdata *dd)
{ {
unsigned i; u16 i;
spin_lock_init(&dd->aspm_lock); spin_lock_init(&dd->aspm_lock);
dd->aspm_supported = aspm_hw_l1_supported(dd); dd->aspm_supported = aspm_hw_l1_supported(dd);
......
此差异已折叠。
...@@ -384,6 +384,7 @@ ...@@ -384,6 +384,7 @@
#define VERIFY_CAP_LOCAL_FABRIC 0x08 #define VERIFY_CAP_LOCAL_FABRIC 0x08
#define VERIFY_CAP_LOCAL_LINK_WIDTH 0x09 #define VERIFY_CAP_LOCAL_LINK_WIDTH 0x09
#define LOCAL_DEVICE_ID 0x0a #define LOCAL_DEVICE_ID 0x0a
#define RESERVED_REGISTERS 0x0b
#define LOCAL_LNI_INFO 0x0c #define LOCAL_LNI_INFO 0x0c
#define REMOTE_LNI_INFO 0x0d #define REMOTE_LNI_INFO 0x0d
#define MISC_STATUS 0x0e #define MISC_STATUS 0x0e
...@@ -506,6 +507,9 @@ ...@@ -506,6 +507,9 @@
#define DOWN_REMOTE_REASON_SHIFT 16 #define DOWN_REMOTE_REASON_SHIFT 16
#define DOWN_REMOTE_REASON_MASK 0xff #define DOWN_REMOTE_REASON_MASK 0xff
#define HOST_INTERFACE_VERSION_SHIFT 16
#define HOST_INTERFACE_VERSION_MASK 0xff
/* verify capability PHY power management bits */ /* verify capability PHY power management bits */
#define PWRM_BER_CONTROL 0x1 #define PWRM_BER_CONTROL 0x1
#define PWRM_BANDWIDTH_CONTROL 0x2 #define PWRM_BANDWIDTH_CONTROL 0x2
...@@ -605,11 +609,11 @@ int read_lcb_csr(struct hfi1_devdata *dd, u32 offset, u64 *data); ...@@ -605,11 +609,11 @@ int read_lcb_csr(struct hfi1_devdata *dd, u32 offset, u64 *data);
int write_lcb_csr(struct hfi1_devdata *dd, u32 offset, u64 data); int write_lcb_csr(struct hfi1_devdata *dd, u32 offset, u64 data);
void __iomem *get_csr_addr( void __iomem *get_csr_addr(
struct hfi1_devdata *dd, const struct hfi1_devdata *dd,
u32 offset); u32 offset);
static inline void __iomem *get_kctxt_csr_addr( static inline void __iomem *get_kctxt_csr_addr(
struct hfi1_devdata *dd, const struct hfi1_devdata *dd,
int ctxt, int ctxt,
u32 offset0) u32 offset0)
{ {
...@@ -704,6 +708,7 @@ int read_8051_data(struct hfi1_devdata *dd, u32 addr, u32 len, u64 *result); ...@@ -704,6 +708,7 @@ int read_8051_data(struct hfi1_devdata *dd, u32 addr, u32 len, u64 *result);
/* chip.c */ /* chip.c */
void read_misc_status(struct hfi1_devdata *dd, u8 *ver_major, u8 *ver_minor, void read_misc_status(struct hfi1_devdata *dd, u8 *ver_major, u8 *ver_minor,
u8 *ver_patch); u8 *ver_patch);
int write_host_interface_version(struct hfi1_devdata *dd, u8 version);
void read_guid(struct hfi1_devdata *dd); void read_guid(struct hfi1_devdata *dd);
int wait_fm_ready(struct hfi1_devdata *dd, u32 mstimeout); int wait_fm_ready(struct hfi1_devdata *dd, u32 mstimeout);
void set_link_down_reason(struct hfi1_pportdata *ppd, u8 lcl_reason, void set_link_down_reason(struct hfi1_pportdata *ppd, u8 lcl_reason,
...@@ -744,6 +749,7 @@ int is_bx(struct hfi1_devdata *dd); ...@@ -744,6 +749,7 @@ int is_bx(struct hfi1_devdata *dd);
u32 read_physical_state(struct hfi1_devdata *dd); u32 read_physical_state(struct hfi1_devdata *dd);
u32 chip_to_opa_pstate(struct hfi1_devdata *dd, u32 chip_pstate); u32 chip_to_opa_pstate(struct hfi1_devdata *dd, u32 chip_pstate);
u32 get_logical_state(struct hfi1_pportdata *ppd); u32 get_logical_state(struct hfi1_pportdata *ppd);
void cache_physical_state(struct hfi1_pportdata *ppd);
const char *opa_lstate_name(u32 lstate); const char *opa_lstate_name(u32 lstate);
const char *opa_pstate_name(u32 pstate); const char *opa_pstate_name(u32 pstate);
u32 driver_physical_state(struct hfi1_pportdata *ppd); u32 driver_physical_state(struct hfi1_pportdata *ppd);
...@@ -1347,21 +1353,21 @@ enum { ...@@ -1347,21 +1353,21 @@ enum {
u64 get_all_cpu_total(u64 __percpu *cntr); u64 get_all_cpu_total(u64 __percpu *cntr);
void hfi1_start_cleanup(struct hfi1_devdata *dd); void hfi1_start_cleanup(struct hfi1_devdata *dd);
void hfi1_clear_tids(struct hfi1_ctxtdata *rcd); void hfi1_clear_tids(struct hfi1_ctxtdata *rcd);
struct ib_header *hfi1_get_msgheader(
struct hfi1_devdata *dd, __le32 *rhf_addr);
void hfi1_init_ctxt(struct send_context *sc); void hfi1_init_ctxt(struct send_context *sc);
void hfi1_put_tid(struct hfi1_devdata *dd, u32 index, void hfi1_put_tid(struct hfi1_devdata *dd, u32 index,
u32 type, unsigned long pa, u16 order); u32 type, unsigned long pa, u16 order);
void hfi1_quiet_serdes(struct hfi1_pportdata *ppd); void hfi1_quiet_serdes(struct hfi1_pportdata *ppd);
void hfi1_rcvctrl(struct hfi1_devdata *dd, unsigned int op, int ctxt); void hfi1_rcvctrl(struct hfi1_devdata *dd, unsigned int op,
struct hfi1_ctxtdata *rcd);
u32 hfi1_read_cntrs(struct hfi1_devdata *dd, char **namep, u64 **cntrp); u32 hfi1_read_cntrs(struct hfi1_devdata *dd, char **namep, u64 **cntrp);
u32 hfi1_read_portcntrs(struct hfi1_pportdata *ppd, char **namep, u64 **cntrp); u32 hfi1_read_portcntrs(struct hfi1_pportdata *ppd, char **namep, u64 **cntrp);
u8 hfi1_ibphys_portstate(struct hfi1_pportdata *ppd);
int hfi1_get_ib_cfg(struct hfi1_pportdata *ppd, int which); int hfi1_get_ib_cfg(struct hfi1_pportdata *ppd, int which);
int hfi1_set_ib_cfg(struct hfi1_pportdata *ppd, int which, u32 val); int hfi1_set_ib_cfg(struct hfi1_pportdata *ppd, int which, u32 val);
int hfi1_set_ctxt_jkey(struct hfi1_devdata *dd, unsigned ctxt, u16 jkey); int hfi1_set_ctxt_jkey(struct hfi1_devdata *dd, struct hfi1_ctxtdata *rcd,
int hfi1_clear_ctxt_jkey(struct hfi1_devdata *dd, unsigned ctxt); u16 jkey);
int hfi1_set_ctxt_pkey(struct hfi1_devdata *dd, unsigned ctxt, u16 pkey); int hfi1_clear_ctxt_jkey(struct hfi1_devdata *dd, struct hfi1_ctxtdata *ctxt);
int hfi1_set_ctxt_pkey(struct hfi1_devdata *dd, struct hfi1_ctxtdata *ctxt,
u16 pkey);
int hfi1_clear_ctxt_pkey(struct hfi1_devdata *dd, struct hfi1_ctxtdata *ctxt); int hfi1_clear_ctxt_pkey(struct hfi1_devdata *dd, struct hfi1_ctxtdata *ctxt);
void hfi1_read_link_quality(struct hfi1_devdata *dd, u8 *link_quality); void hfi1_read_link_quality(struct hfi1_devdata *dd, u8 *link_quality);
void hfi1_init_vnic_rsm(struct hfi1_devdata *dd); void hfi1_init_vnic_rsm(struct hfi1_devdata *dd);
......
...@@ -325,6 +325,7 @@ struct diag_pkt { ...@@ -325,6 +325,7 @@ struct diag_pkt {
#define HFI1_LRH_BTH 0x0002 /* 1. word of IB LRH - next header: BTH */ #define HFI1_LRH_BTH 0x0002 /* 1. word of IB LRH - next header: BTH */
/* misc. */ /* misc. */
#define SC15_PACKET 0xF
#define SIZE_OF_CRC 1 #define SIZE_OF_CRC 1
#define LIM_MGMT_P_KEY 0x7FFF #define LIM_MGMT_P_KEY 0x7FFF
......
...@@ -96,7 +96,6 @@ MODULE_PARM_DESC(cap_mask, "Bit mask of enabled/disabled HW features"); ...@@ -96,7 +96,6 @@ MODULE_PARM_DESC(cap_mask, "Bit mask of enabled/disabled HW features");
MODULE_LICENSE("Dual BSD/GPL"); MODULE_LICENSE("Dual BSD/GPL");
MODULE_DESCRIPTION("Intel Omni-Path Architecture driver"); MODULE_DESCRIPTION("Intel Omni-Path Architecture driver");
MODULE_VERSION(HFI1_DRIVER_VERSION);
/* /*
* MAX_PKT_RCV is the max # if packets processed per receive interrupt. * MAX_PKT_RCV is the max # if packets processed per receive interrupt.
...@@ -196,7 +195,7 @@ int hfi1_count_active_units(void) ...@@ -196,7 +195,7 @@ int hfi1_count_active_units(void)
spin_lock_irqsave(&hfi1_devs_lock, flags); spin_lock_irqsave(&hfi1_devs_lock, flags);
list_for_each_entry(dd, &hfi1_dev_list, list) { list_for_each_entry(dd, &hfi1_dev_list, list) {
if (!(dd->flags & HFI1_PRESENT) || !dd->kregbase) if (!(dd->flags & HFI1_PRESENT) || !dd->kregbase1)
continue; continue;
for (pidx = 0; pidx < dd->num_pports; ++pidx) { for (pidx = 0; pidx < dd->num_pports; ++pidx) {
ppd = dd->pport + pidx; ppd = dd->pport + pidx;
...@@ -224,6 +223,20 @@ static inline void *get_egrbuf(const struct hfi1_ctxtdata *rcd, u64 rhf, ...@@ -224,6 +223,20 @@ static inline void *get_egrbuf(const struct hfi1_ctxtdata *rcd, u64 rhf,
(offset * RCV_BUF_BLOCK_SIZE)); (offset * RCV_BUF_BLOCK_SIZE));
} }
static inline void *hfi1_get_header(struct hfi1_devdata *dd,
__le32 *rhf_addr)
{
u32 offset = rhf_hdrq_offset(rhf_to_cpu(rhf_addr));
return (void *)(rhf_addr - dd->rhf_offset + offset);
}
static inline struct ib_header *hfi1_get_msgheader(struct hfi1_devdata *dd,
__le32 *rhf_addr)
{
return (struct ib_header *)hfi1_get_header(dd, rhf_addr);
}
/* /*
* Validate and encode the a given RcvArray Buffer size. * Validate and encode the a given RcvArray Buffer size.
* The function will check whether the given size falls within * The function will check whether the given size falls within
...@@ -249,7 +262,8 @@ static void rcv_hdrerr(struct hfi1_ctxtdata *rcd, struct hfi1_pportdata *ppd, ...@@ -249,7 +262,8 @@ static void rcv_hdrerr(struct hfi1_ctxtdata *rcd, struct hfi1_pportdata *ppd,
{ {
struct ib_header *rhdr = packet->hdr; struct ib_header *rhdr = packet->hdr;
u32 rte = rhf_rcv_type_err(packet->rhf); u32 rte = rhf_rcv_type_err(packet->rhf);
int lnh = ib_get_lnh(rhdr); u8 lnh = ib_get_lnh(rhdr);
bool has_grh = false;
struct hfi1_ibport *ibp = rcd_to_iport(rcd); struct hfi1_ibport *ibp = rcd_to_iport(rcd);
struct hfi1_devdata *dd = ppd->dd; struct hfi1_devdata *dd = ppd->dd;
struct rvt_dev_info *rdi = &dd->verbs_dev.rdi; struct rvt_dev_info *rdi = &dd->verbs_dev.rdi;
...@@ -257,37 +271,42 @@ static void rcv_hdrerr(struct hfi1_ctxtdata *rcd, struct hfi1_pportdata *ppd, ...@@ -257,37 +271,42 @@ static void rcv_hdrerr(struct hfi1_ctxtdata *rcd, struct hfi1_pportdata *ppd,
if (packet->rhf & (RHF_VCRC_ERR | RHF_ICRC_ERR)) if (packet->rhf & (RHF_VCRC_ERR | RHF_ICRC_ERR))
return; return;
if (lnh == HFI1_LRH_BTH) {
packet->ohdr = &rhdr->u.oth;
} else if (lnh == HFI1_LRH_GRH) {
has_grh = true;
packet->ohdr = &rhdr->u.l.oth;
packet->grh = &rhdr->u.l.grh;
} else {
goto drop;
}
if (packet->rhf & RHF_TID_ERR) { if (packet->rhf & RHF_TID_ERR) {
/* For TIDERR and RC QPs preemptively schedule a NAK */ /* For TIDERR and RC QPs preemptively schedule a NAK */
struct ib_other_headers *ohdr = NULL;
u32 tlen = rhf_pkt_len(packet->rhf); /* in bytes */ u32 tlen = rhf_pkt_len(packet->rhf); /* in bytes */
u16 lid = ib_get_dlid(rhdr); u32 dlid = ib_get_dlid(rhdr);
u32 qp_num; u32 qp_num;
u32 rcv_flags = 0; u32 mlid_base = be16_to_cpu(IB_MULTICAST_LID_BASE);
/* Sanity check packet */ /* Sanity check packet */
if (tlen < 24) if (tlen < 24)
goto drop; goto drop;
/* Check for GRH */ /* Check for GRH */
if (lnh == HFI1_LRH_BTH) { if (has_grh) {
ohdr = &rhdr->u.oth;
} else if (lnh == HFI1_LRH_GRH) {
u32 vtf; u32 vtf;
struct ib_grh *grh = packet->grh;
ohdr = &rhdr->u.l.oth; if (grh->next_hdr != IB_GRH_NEXT_HDR)
if (rhdr->u.l.grh.next_hdr != IB_GRH_NEXT_HDR)
goto drop; goto drop;
vtf = be32_to_cpu(rhdr->u.l.grh.version_tclass_flow); vtf = be32_to_cpu(grh->version_tclass_flow);
if ((vtf >> IB_GRH_VERSION_SHIFT) != IB_GRH_VERSION) if ((vtf >> IB_GRH_VERSION_SHIFT) != IB_GRH_VERSION)
goto drop; goto drop;
rcv_flags |= HFI1_HAS_GRH;
} else {
goto drop;
} }
/* Get the destination QP number. */ /* Get the destination QP number. */
qp_num = be32_to_cpu(ohdr->bth[1]) & RVT_QPN_MASK; qp_num = ib_bth_get_qpn(packet->ohdr);
if (lid < be16_to_cpu(IB_MULTICAST_LID_BASE)) { if (dlid < mlid_base) {
struct rvt_qp *qp; struct rvt_qp *qp;
unsigned long flags; unsigned long flags;
...@@ -312,11 +331,7 @@ static void rcv_hdrerr(struct hfi1_ctxtdata *rcd, struct hfi1_pportdata *ppd, ...@@ -312,11 +331,7 @@ static void rcv_hdrerr(struct hfi1_ctxtdata *rcd, struct hfi1_pportdata *ppd,
switch (qp->ibqp.qp_type) { switch (qp->ibqp.qp_type) {
case IB_QPT_RC: case IB_QPT_RC:
hfi1_rc_hdrerr( hfi1_rc_hdrerr(rcd, packet, qp);
rcd,
rhdr,
rcv_flags,
qp);
break; break;
default: default:
/* For now don't handle any other QP types */ /* For now don't handle any other QP types */
...@@ -332,9 +347,8 @@ static void rcv_hdrerr(struct hfi1_ctxtdata *rcd, struct hfi1_pportdata *ppd, ...@@ -332,9 +347,8 @@ static void rcv_hdrerr(struct hfi1_ctxtdata *rcd, struct hfi1_pportdata *ppd,
switch (rte) { switch (rte) {
case RHF_RTE_ERROR_OP_CODE_ERR: case RHF_RTE_ERROR_OP_CODE_ERR:
{ {
u32 opcode;
void *ebuf = NULL; void *ebuf = NULL;
__be32 *bth = NULL; u8 opcode;
if (rhf_use_egr_bfr(packet->rhf)) if (rhf_use_egr_bfr(packet->rhf))
ebuf = packet->ebuf; ebuf = packet->ebuf;
...@@ -342,16 +356,7 @@ static void rcv_hdrerr(struct hfi1_ctxtdata *rcd, struct hfi1_pportdata *ppd, ...@@ -342,16 +356,7 @@ static void rcv_hdrerr(struct hfi1_ctxtdata *rcd, struct hfi1_pportdata *ppd,
if (!ebuf) if (!ebuf)
goto drop; /* this should never happen */ goto drop; /* this should never happen */
if (lnh == HFI1_LRH_BTH) opcode = ib_bth_get_opcode(packet->ohdr);
bth = (__be32 *)ebuf;
else if (lnh == HFI1_LRH_GRH)
bth = (__be32 *)((char *)ebuf + sizeof(struct ib_grh));
else
goto drop;
opcode = be32_to_cpu(bth[0]) >> 24;
opcode &= 0xff;
if (opcode == IB_OPCODE_CNP) { if (opcode == IB_OPCODE_CNP) {
/* /*
* Only in pre-B0 h/w is the CNP_OPCODE handled * Only in pre-B0 h/w is the CNP_OPCODE handled
...@@ -365,7 +370,7 @@ static void rcv_hdrerr(struct hfi1_ctxtdata *rcd, struct hfi1_pportdata *ppd, ...@@ -365,7 +370,7 @@ static void rcv_hdrerr(struct hfi1_ctxtdata *rcd, struct hfi1_pportdata *ppd,
sc5 = hfi1_9B_get_sc5(rhdr, packet->rhf); sc5 = hfi1_9B_get_sc5(rhdr, packet->rhf);
sl = ibp->sc_to_sl[sc5]; sl = ibp->sc_to_sl[sc5];
lqpn = be32_to_cpu(bth[1]) & RVT_QPN_MASK; lqpn = ib_bth_get_qpn(packet->ohdr);
rcu_read_lock(); rcu_read_lock();
qp = rvt_lookup_qpn(rdi, &ibp->rvp, lqpn); qp = rvt_lookup_qpn(rdi, &ibp->rvp, lqpn);
if (!qp) { if (!qp) {
...@@ -415,7 +420,6 @@ static inline void init_packet(struct hfi1_ctxtdata *rcd, ...@@ -415,7 +420,6 @@ static inline void init_packet(struct hfi1_ctxtdata *rcd,
packet->rhf = rhf_to_cpu(packet->rhf_addr); packet->rhf = rhf_to_cpu(packet->rhf_addr);
packet->rhqoff = rcd->head; packet->rhqoff = rcd->head;
packet->numpkt = 0; packet->numpkt = 0;
packet->rcv_flags = 0;
} }
void hfi1_process_ecn_slowpath(struct rvt_qp *qp, struct hfi1_packet *pkt, void hfi1_process_ecn_slowpath(struct rvt_qp *qp, struct hfi1_packet *pkt,
...@@ -424,21 +428,18 @@ void hfi1_process_ecn_slowpath(struct rvt_qp *qp, struct hfi1_packet *pkt, ...@@ -424,21 +428,18 @@ void hfi1_process_ecn_slowpath(struct rvt_qp *qp, struct hfi1_packet *pkt,
struct hfi1_ibport *ibp = to_iport(qp->ibqp.device, qp->port_num); struct hfi1_ibport *ibp = to_iport(qp->ibqp.device, qp->port_num);
struct ib_header *hdr = pkt->hdr; struct ib_header *hdr = pkt->hdr;
struct ib_other_headers *ohdr = pkt->ohdr; struct ib_other_headers *ohdr = pkt->ohdr;
struct ib_grh *grh = NULL; struct ib_grh *grh = pkt->grh;
u32 rqpn = 0, bth1; u32 rqpn = 0, bth1;
u16 rlid, dlid = ib_get_dlid(hdr); u16 rlid, dlid = ib_get_dlid(hdr);
u8 sc, svc_type; u8 sc, svc_type;
bool is_mcast = false; bool is_mcast = false;
if (pkt->rcv_flags & HFI1_HAS_GRH)
grh = &hdr->u.l.grh;
switch (qp->ibqp.qp_type) { switch (qp->ibqp.qp_type) {
case IB_QPT_SMI: case IB_QPT_SMI:
case IB_QPT_GSI: case IB_QPT_GSI:
case IB_QPT_UD: case IB_QPT_UD:
rlid = ib_get_slid(hdr); rlid = ib_get_slid(hdr);
rqpn = be32_to_cpu(ohdr->u.ud.deth[1]) & RVT_QPN_MASK; rqpn = ib_get_sqpn(ohdr);
svc_type = IB_CC_SVCTYPE_UD; svc_type = IB_CC_SVCTYPE_UD;
is_mcast = (dlid > be16_to_cpu(IB_MULTICAST_LID_BASE)) && is_mcast = (dlid > be16_to_cpu(IB_MULTICAST_LID_BASE)) &&
(dlid != be16_to_cpu(IB_LID_PERMISSIVE)); (dlid != be16_to_cpu(IB_LID_PERMISSIVE));
...@@ -461,7 +462,7 @@ void hfi1_process_ecn_slowpath(struct rvt_qp *qp, struct hfi1_packet *pkt, ...@@ -461,7 +462,7 @@ void hfi1_process_ecn_slowpath(struct rvt_qp *qp, struct hfi1_packet *pkt,
bth1 = be32_to_cpu(ohdr->bth[1]); bth1 = be32_to_cpu(ohdr->bth[1]);
if (do_cnp && (bth1 & IB_FECN_SMASK)) { if (do_cnp && (bth1 & IB_FECN_SMASK)) {
u16 pkey = (u16)be32_to_cpu(ohdr->bth[0]); u16 pkey = ib_bth_get_pkey(ohdr);
return_cnp(ibp, qp, rqpn, pkey, dlid, rlid, sc, grh); return_cnp(ibp, qp, rqpn, pkey, dlid, rlid, sc, grh);
} }
...@@ -591,9 +592,10 @@ static void __prescan_rxq(struct hfi1_packet *packet) ...@@ -591,9 +592,10 @@ static void __prescan_rxq(struct hfi1_packet *packet)
if (lnh == HFI1_LRH_BTH) { if (lnh == HFI1_LRH_BTH) {
packet->ohdr = &hdr->u.oth; packet->ohdr = &hdr->u.oth;
packet->grh = NULL;
} else if (lnh == HFI1_LRH_GRH) { } else if (lnh == HFI1_LRH_GRH) {
packet->ohdr = &hdr->u.l.oth; packet->ohdr = &hdr->u.l.oth;
packet->rcv_flags |= HFI1_HAS_GRH; packet->grh = &hdr->u.l.grh;
} else { } else {
goto next; /* just in case */ goto next; /* just in case */
} }
...@@ -698,10 +700,8 @@ static inline int process_rcv_packet(struct hfi1_packet *packet, int thread) ...@@ -698,10 +700,8 @@ static inline int process_rcv_packet(struct hfi1_packet *packet, int thread)
{ {
int ret; int ret;
packet->hdr = hfi1_get_msgheader(packet->rcd->dd,
packet->rhf_addr);
packet->hlen = (u8 *)packet->rhf_addr - (u8 *)packet->hdr;
packet->etype = rhf_rcv_type(packet->rhf); packet->etype = rhf_rcv_type(packet->rhf);
/* total length */ /* total length */
packet->tlen = rhf_pkt_len(packet->rhf); /* in bytes */ packet->tlen = rhf_pkt_len(packet->rhf); /* in bytes */
/* retrieve eager buffer details */ /* retrieve eager buffer details */
...@@ -759,7 +759,7 @@ static inline void process_rcv_update(int last, struct hfi1_packet *packet) ...@@ -759,7 +759,7 @@ static inline void process_rcv_update(int last, struct hfi1_packet *packet)
packet->etail, 0, 0); packet->etail, 0, 0);
packet->updegr = 0; packet->updegr = 0;
} }
packet->rcv_flags = 0; packet->grh = NULL;
} }
static inline void finish_packet(struct hfi1_packet *packet) static inline void finish_packet(struct hfi1_packet *packet)
...@@ -837,9 +837,9 @@ int handle_receive_interrupt_dma_rtail(struct hfi1_ctxtdata *rcd, int thread) ...@@ -837,9 +837,9 @@ int handle_receive_interrupt_dma_rtail(struct hfi1_ctxtdata *rcd, int thread)
return last; return last;
} }
static inline void set_nodma_rtail(struct hfi1_devdata *dd, u8 ctxt) static inline void set_nodma_rtail(struct hfi1_devdata *dd, u16 ctxt)
{ {
int i; u16 i;
/* /*
* For dynamically allocated kernel contexts (like vnic) switch * For dynamically allocated kernel contexts (like vnic) switch
...@@ -857,9 +857,9 @@ static inline void set_nodma_rtail(struct hfi1_devdata *dd, u8 ctxt) ...@@ -857,9 +857,9 @@ static inline void set_nodma_rtail(struct hfi1_devdata *dd, u8 ctxt)
&handle_receive_interrupt_nodma_rtail; &handle_receive_interrupt_nodma_rtail;
} }
static inline void set_dma_rtail(struct hfi1_devdata *dd, u8 ctxt) static inline void set_dma_rtail(struct hfi1_devdata *dd, u16 ctxt)
{ {
int i; u16 i;
/* /*
* For dynamically allocated kernel contexts (like vnic) switch * For dynamically allocated kernel contexts (like vnic) switch
...@@ -879,7 +879,7 @@ static inline void set_dma_rtail(struct hfi1_devdata *dd, u8 ctxt) ...@@ -879,7 +879,7 @@ static inline void set_dma_rtail(struct hfi1_devdata *dd, u8 ctxt)
void set_all_slowpath(struct hfi1_devdata *dd) void set_all_slowpath(struct hfi1_devdata *dd)
{ {
int i; u16 i;
/* HFI1_CTRL_CTXT must always use the slow path interrupt handler */ /* HFI1_CTRL_CTXT must always use the slow path interrupt handler */
for (i = HFI1_CTRL_CTXT + 1; i < dd->num_rcv_contexts; i++) { for (i = HFI1_CTRL_CTXT + 1; i < dd->num_rcv_contexts; i++) {
...@@ -896,20 +896,25 @@ static inline int set_armed_to_active(struct hfi1_ctxtdata *rcd, ...@@ -896,20 +896,25 @@ static inline int set_armed_to_active(struct hfi1_ctxtdata *rcd,
struct hfi1_devdata *dd) struct hfi1_devdata *dd)
{ {
struct work_struct *lsaw = &rcd->ppd->linkstate_active_work; struct work_struct *lsaw = &rcd->ppd->linkstate_active_work;
struct ib_header *hdr = hfi1_get_msgheader(packet->rcd->dd,
packet->rhf_addr);
u8 etype = rhf_rcv_type(packet->rhf); u8 etype = rhf_rcv_type(packet->rhf);
u8 sc = SC15_PACKET;
if (etype == RHF_RCV_TYPE_IB && if (etype == RHF_RCV_TYPE_IB) {
hfi1_9B_get_sc5(hdr, packet->rhf) != 0xf) { struct ib_header *hdr = hfi1_get_msgheader(packet->rcd->dd,
int hwstate = read_logical_state(dd); packet->rhf_addr);
sc = hfi1_9B_get_sc5(hdr, packet->rhf);
}
if (sc != SC15_PACKET) {
int hwstate = driver_lstate(rcd->ppd);
if (hwstate != LSTATE_ACTIVE) { if (hwstate != IB_PORT_ACTIVE) {
dd_dev_info(dd, "Unexpected link state %d\n", hwstate); dd_dev_info(dd,
"Unexpected link state %s\n",
opa_lstate_name(hwstate));
return 0; return 0;
} }
queue_work(rcd->ppd->hfi1_wq, lsaw); queue_work(rcd->ppd->link_wq, lsaw);
return 1; return 1;
} }
return 0; return 0;
...@@ -1063,7 +1068,7 @@ void receive_interrupt_work(struct work_struct *work) ...@@ -1063,7 +1068,7 @@ void receive_interrupt_work(struct work_struct *work)
struct hfi1_pportdata *ppd = container_of(work, struct hfi1_pportdata, struct hfi1_pportdata *ppd = container_of(work, struct hfi1_pportdata,
linkstate_active_work); linkstate_active_work);
struct hfi1_devdata *dd = ppd->dd; struct hfi1_devdata *dd = ppd->dd;
int i; u16 i;
/* Received non-SC15 packet implies neighbor_normal */ /* Received non-SC15 packet implies neighbor_normal */
ppd->neighbor_normal = 1; ppd->neighbor_normal = 1;
...@@ -1264,7 +1269,8 @@ void hfi1_start_led_override(struct hfi1_pportdata *ppd, unsigned int timeon, ...@@ -1264,7 +1269,8 @@ void hfi1_start_led_override(struct hfi1_pportdata *ppd, unsigned int timeon,
*/ */
int hfi1_reset_device(int unit) int hfi1_reset_device(int unit)
{ {
int ret, i; int ret;
u16 i;
struct hfi1_devdata *dd = hfi1_lookup(unit); struct hfi1_devdata *dd = hfi1_lookup(unit);
struct hfi1_pportdata *ppd; struct hfi1_pportdata *ppd;
unsigned long flags; unsigned long flags;
...@@ -1277,7 +1283,7 @@ int hfi1_reset_device(int unit) ...@@ -1277,7 +1283,7 @@ int hfi1_reset_device(int unit)
dd_dev_info(dd, "Reset on unit %u requested\n", unit); dd_dev_info(dd, "Reset on unit %u requested\n", unit);
if (!dd->kregbase || !(dd->flags & HFI1_PRESENT)) { if (!dd->kregbase1 || !(dd->flags & HFI1_PRESENT)) {
dd_dev_info(dd, dd_dev_info(dd,
"Invalid unit number %u or not initialized or not present\n", "Invalid unit number %u or not initialized or not present\n",
unit); unit);
...@@ -1321,6 +1327,58 @@ int hfi1_reset_device(int unit) ...@@ -1321,6 +1327,58 @@ int hfi1_reset_device(int unit)
return ret; return ret;
} }
static inline void hfi1_setup_ib_header(struct hfi1_packet *packet)
{
packet->hdr = (struct hfi1_ib_message_header *)
hfi1_get_msgheader(packet->rcd->dd,
packet->rhf_addr);
packet->hlen = (u8 *)packet->rhf_addr - (u8 *)packet->hdr;
}
static int hfi1_setup_9B_packet(struct hfi1_packet *packet)
{
struct hfi1_ibport *ibp = rcd_to_iport(packet->rcd);
struct ib_header *hdr;
u8 lnh;
hfi1_setup_ib_header(packet);
hdr = packet->hdr;
lnh = ib_get_lnh(hdr);
if (lnh == HFI1_LRH_BTH) {
packet->ohdr = &hdr->u.oth;
packet->grh = NULL;
} else if (lnh == HFI1_LRH_GRH) {
u32 vtf;
packet->ohdr = &hdr->u.l.oth;
packet->grh = &hdr->u.l.grh;
if (packet->grh->next_hdr != IB_GRH_NEXT_HDR)
goto drop;
vtf = be32_to_cpu(packet->grh->version_tclass_flow);
if ((vtf >> IB_GRH_VERSION_SHIFT) != IB_GRH_VERSION)
goto drop;
} else {
goto drop;
}
/* Query commonly used fields from packet header */
packet->opcode = ib_bth_get_opcode(packet->ohdr);
packet->slid = ib_get_slid(hdr);
packet->dlid = ib_get_dlid(hdr);
packet->sl = ib_get_sl(hdr);
packet->sc = hfi1_9B_get_sc5(hdr, packet->rhf);
packet->pad = ib_bth_get_pad(packet->ohdr);
packet->extra_byte = 0;
packet->fecn = ib_bth_get_fecn(packet->ohdr);
packet->becn = ib_bth_get_becn(packet->ohdr);
return 0;
drop:
ibp->rvp.n_pkt_drops++;
return -EINVAL;
}
void handle_eflags(struct hfi1_packet *packet) void handle_eflags(struct hfi1_packet *packet)
{ {
struct hfi1_ctxtdata *rcd = packet->rcd; struct hfi1_ctxtdata *rcd = packet->rcd;
...@@ -1351,6 +1409,9 @@ int process_receive_ib(struct hfi1_packet *packet) ...@@ -1351,6 +1409,9 @@ int process_receive_ib(struct hfi1_packet *packet)
if (unlikely(hfi1_dbg_fault_packet(packet))) if (unlikely(hfi1_dbg_fault_packet(packet)))
return RHF_RCV_CONTINUE; return RHF_RCV_CONTINUE;
if (hfi1_setup_9B_packet(packet))
return RHF_RCV_CONTINUE;
trace_hfi1_rcvhdr(packet->rcd->ppd->dd, trace_hfi1_rcvhdr(packet->rcd->ppd->dd,
packet->rcd->ctxt, packet->rcd->ctxt,
rhf_err_flags(packet->rhf), rhf_err_flags(packet->rhf),
...@@ -1422,6 +1483,7 @@ int process_receive_error(struct hfi1_packet *packet) ...@@ -1422,6 +1483,7 @@ int process_receive_error(struct hfi1_packet *packet)
rhf_rcv_type_err(packet->rhf) == 3)) rhf_rcv_type_err(packet->rhf) == 3))
return RHF_RCV_CONTINUE; return RHF_RCV_CONTINUE;
hfi1_setup_ib_header(packet);
handle_eflags(packet); handle_eflags(packet);
if (unlikely(rhf_err_flags(packet->rhf))) if (unlikely(rhf_err_flags(packet->rhf)))
...@@ -1435,6 +1497,8 @@ int kdeth_process_expected(struct hfi1_packet *packet) ...@@ -1435,6 +1497,8 @@ int kdeth_process_expected(struct hfi1_packet *packet)
{ {
if (unlikely(hfi1_dbg_fault_packet(packet))) if (unlikely(hfi1_dbg_fault_packet(packet)))
return RHF_RCV_CONTINUE; return RHF_RCV_CONTINUE;
hfi1_setup_ib_header(packet);
if (unlikely(rhf_err_flags(packet->rhf))) if (unlikely(rhf_err_flags(packet->rhf)))
handle_eflags(packet); handle_eflags(packet);
...@@ -1445,6 +1509,7 @@ int kdeth_process_expected(struct hfi1_packet *packet) ...@@ -1445,6 +1509,7 @@ int kdeth_process_expected(struct hfi1_packet *packet)
int kdeth_process_eager(struct hfi1_packet *packet) int kdeth_process_eager(struct hfi1_packet *packet)
{ {
hfi1_setup_ib_header(packet);
if (unlikely(rhf_err_flags(packet->rhf))) if (unlikely(rhf_err_flags(packet->rhf)))
handle_eflags(packet); handle_eflags(packet);
if (unlikely(hfi1_dbg_fault_packet(packet))) if (unlikely(hfi1_dbg_fault_packet(packet)))
......
...@@ -250,7 +250,6 @@ static int read_partition_platform_config(struct hfi1_devdata *dd, void **data, ...@@ -250,7 +250,6 @@ static int read_partition_platform_config(struct hfi1_devdata *dd, void **data,
{ {
void *buffer; void *buffer;
void *p; void *p;
u32 length;
int ret; int ret;
buffer = kmalloc(P1_SIZE, GFP_KERNEL); buffer = kmalloc(P1_SIZE, GFP_KERNEL);
...@@ -265,13 +264,13 @@ static int read_partition_platform_config(struct hfi1_devdata *dd, void **data, ...@@ -265,13 +264,13 @@ static int read_partition_platform_config(struct hfi1_devdata *dd, void **data,
/* scan for image magic that may trail the actual data */ /* scan for image magic that may trail the actual data */
p = strnstr(buffer, IMAGE_TRAIL_MAGIC, P1_SIZE); p = strnstr(buffer, IMAGE_TRAIL_MAGIC, P1_SIZE);
if (p) if (!p) {
length = p - buffer; kfree(buffer);
else return -ENOENT;
length = P1_SIZE; }
*data = buffer; *data = buffer;
*size = length; *size = p - buffer;
return 0; return 0;
} }
......
/*
* 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.
*
*/
#include "exp_rcv.h"
#include "trace.h"
/**
* exp_tid_group_init - initialize exp_tid_set
* @set - the set
*/
void hfi1_exp_tid_group_init(struct exp_tid_set *set)
{
INIT_LIST_HEAD(&set->list);
set->count = 0;
}
/**
* alloc_ctxt_rcv_groups - initialize expected receive groups
* @rcd - the context to add the groupings to
*/
int hfi1_alloc_ctxt_rcv_groups(struct hfi1_ctxtdata *rcd)
{
struct hfi1_devdata *dd = rcd->dd;
u32 tidbase;
struct tid_group *grp;
int i;
tidbase = rcd->expected_base;
for (i = 0; i < rcd->expected_count /
dd->rcv_entries.group_size; i++) {
grp = kzalloc(sizeof(*grp), GFP_KERNEL);
if (!grp)
goto bail;
grp->size = dd->rcv_entries.group_size;
grp->base = tidbase;
tid_group_add_tail(grp, &rcd->tid_group_list);
tidbase += dd->rcv_entries.group_size;
}
return 0;
bail:
hfi1_free_ctxt_rcv_groups(rcd);
return -ENOMEM;
}
/**
* free_ctxt_rcv_groups - free expected receive groups
* @rcd - the context to free
*
* The routine dismantles the expect receive linked
* list and clears any tids associated with the receive
* context.
*
* This should only be called for kernel contexts and the
* a base user context.
*/
void hfi1_free_ctxt_rcv_groups(struct hfi1_ctxtdata *rcd)
{
struct tid_group *grp, *gptr;
WARN_ON(!EXP_TID_SET_EMPTY(rcd->tid_full_list));
WARN_ON(!EXP_TID_SET_EMPTY(rcd->tid_used_list));
list_for_each_entry_safe(grp, gptr, &rcd->tid_group_list.list, list) {
tid_group_remove(grp, &rcd->tid_group_list);
kfree(grp);
}
hfi1_clear_tids(rcd);
}
此差异已折叠。
...@@ -69,6 +69,7 @@ ...@@ -69,6 +69,7 @@
#define ALT_FW_FABRIC_NAME "hfi1_fabric_d.fw" #define ALT_FW_FABRIC_NAME "hfi1_fabric_d.fw"
#define ALT_FW_SBUS_NAME "hfi1_sbus_d.fw" #define ALT_FW_SBUS_NAME "hfi1_sbus_d.fw"
#define ALT_FW_PCIE_NAME "hfi1_pcie_d.fw" #define ALT_FW_PCIE_NAME "hfi1_pcie_d.fw"
#define HOST_INTERFACE_VERSION 1
static uint fw_8051_load = 1; static uint fw_8051_load = 1;
static uint fw_fabric_serdes_load = 1; static uint fw_fabric_serdes_load = 1;
...@@ -615,6 +616,14 @@ static void __obtain_firmware(struct hfi1_devdata *dd) ...@@ -615,6 +616,14 @@ static void __obtain_firmware(struct hfi1_devdata *dd)
fw_fabric_serdes_name = ALT_FW_FABRIC_NAME; fw_fabric_serdes_name = ALT_FW_FABRIC_NAME;
fw_sbus_name = ALT_FW_SBUS_NAME; fw_sbus_name = ALT_FW_SBUS_NAME;
fw_pcie_serdes_name = ALT_FW_PCIE_NAME; fw_pcie_serdes_name = ALT_FW_PCIE_NAME;
/*
* Add a delay before obtaining and loading debug firmware.
* Authorization will fail if the delay between firmware
* authorization events is shorter than 50us. Add 100us to
* make a delay time safe.
*/
usleep_range(100, 120);
} }
if (fw_sbus_load) { if (fw_sbus_load) {
...@@ -1079,6 +1088,13 @@ static int load_8051_firmware(struct hfi1_devdata *dd, ...@@ -1079,6 +1088,13 @@ static int load_8051_firmware(struct hfi1_devdata *dd,
dd_dev_info(dd, "8051 firmware version %d.%d.%d\n", dd_dev_info(dd, "8051 firmware version %d.%d.%d\n",
(int)ver_major, (int)ver_minor, (int)ver_patch); (int)ver_major, (int)ver_minor, (int)ver_patch);
dd->dc8051_ver = dc8051_ver(ver_major, ver_minor, ver_patch); dd->dc8051_ver = dc8051_ver(ver_major, ver_minor, ver_patch);
ret = write_host_interface_version(dd, HOST_INTERFACE_VERSION);
if (ret != HCMD_SUCCESS) {
dd_dev_err(dd,
"Failed to set host interface version, return 0x%x\n",
ret);
return -EIO;
}
return 0; return 0;
} }
......
此差异已折叠。
此差异已折叠。
...@@ -164,6 +164,7 @@ void handle_linkup_change(struct hfi1_devdata *dd, u32 linkup) ...@@ -164,6 +164,7 @@ void handle_linkup_change(struct hfi1_devdata *dd, u32 linkup)
ppd->linkup = 0; ppd->linkup = 0;
/* clear HW details of the previous connection */ /* clear HW details of the previous connection */
ppd->actual_vls_operational = 0;
reset_link_credits(dd); reset_link_credits(dd);
/* freeze after a link down to guarantee a clean egress */ /* freeze after a link down to guarantee a clean egress */
...@@ -196,7 +197,7 @@ void handle_user_interrupt(struct hfi1_ctxtdata *rcd) ...@@ -196,7 +197,7 @@ void handle_user_interrupt(struct hfi1_ctxtdata *rcd)
if (test_and_clear_bit(HFI1_CTXT_WAITING_RCV, &rcd->event_flags)) { if (test_and_clear_bit(HFI1_CTXT_WAITING_RCV, &rcd->event_flags)) {
wake_up_interruptible(&rcd->wait); wake_up_interruptible(&rcd->wait);
hfi1_rcvctrl(dd, HFI1_RCVCTRL_INTRAVAIL_DIS, rcd->ctxt); hfi1_rcvctrl(dd, HFI1_RCVCTRL_INTRAVAIL_DIS, rcd);
} else if (test_and_clear_bit(HFI1_CTXT_WAITING_URG, } else if (test_and_clear_bit(HFI1_CTXT_WAITING_URG,
&rcd->event_flags)) { &rcd->event_flags)) {
rcd->urgent++; rcd->urgent++;
......
...@@ -106,7 +106,9 @@ struct iowait { ...@@ -106,7 +106,9 @@ struct iowait {
struct sdma_engine *sde, struct sdma_engine *sde,
struct iowait *wait, struct iowait *wait,
struct sdma_txreq *tx, struct sdma_txreq *tx,
unsigned seq); uint seq,
bool pkts_sent
);
void (*wakeup)(struct iowait *wait, int reason); void (*wakeup)(struct iowait *wait, int reason);
void (*sdma_drained)(struct iowait *wait); void (*sdma_drained)(struct iowait *wait);
seqlock_t *lock; seqlock_t *lock;
...@@ -118,6 +120,7 @@ struct iowait { ...@@ -118,6 +120,7 @@ struct iowait {
u32 count; u32 count;
u32 tx_limit; u32 tx_limit;
u32 tx_count; u32 tx_count;
u8 starved_cnt;
}; };
#define SDMA_AVAIL_REASON 0 #define SDMA_AVAIL_REASON 0
...@@ -143,7 +146,8 @@ static inline void iowait_init( ...@@ -143,7 +146,8 @@ static inline void iowait_init(
struct sdma_engine *sde, struct sdma_engine *sde,
struct iowait *wait, struct iowait *wait,
struct sdma_txreq *tx, struct sdma_txreq *tx,
unsigned seq), uint seq,
bool pkts_sent),
void (*wakeup)(struct iowait *wait, int reason), void (*wakeup)(struct iowait *wait, int reason),
void (*sdma_drained)(struct iowait *wait)) void (*sdma_drained)(struct iowait *wait))
{ {
...@@ -305,4 +309,66 @@ static inline struct sdma_txreq *iowait_get_txhead(struct iowait *wait) ...@@ -305,4 +309,66 @@ static inline struct sdma_txreq *iowait_get_txhead(struct iowait *wait)
return tx; return tx;
} }
/**
* iowait_queue - Put the iowait on a wait queue
* @pkts_sent: have some packets been sent before queuing?
* @w: the iowait struct
* @wait_head: the wait queue
*
* This function is called to insert an iowait struct into a
* wait queue after a resource (eg, sdma decriptor or pio
* buffer) is run out.
*/
static inline void iowait_queue(bool pkts_sent, struct iowait *w,
struct list_head *wait_head)
{
/*
* To play fair, insert the iowait at the tail of the wait queue if it
* has already sent some packets; Otherwise, put it at the head.
*/
if (pkts_sent) {
list_add_tail(&w->list, wait_head);
w->starved_cnt = 0;
} else {
list_add(&w->list, wait_head);
w->starved_cnt++;
}
}
/**
* iowait_starve_clear - clear the wait queue's starve count
* @pkts_sent: have some packets been sent?
* @w: the iowait struct
*
* This function is called to clear the starve count. If no
* packets have been sent, the starve count will not be cleared.
*/
static inline void iowait_starve_clear(bool pkts_sent, struct iowait *w)
{
if (pkts_sent)
w->starved_cnt = 0;
}
/**
* iowait_starve_find_max - Find the maximum of the starve count
* @w: the iowait struct
* @max: a variable containing the max starve count
* @idx: the index of the current iowait in an array
* @max_idx: a variable containing the array index for the
* iowait entry that has the max starve count
*
* This function is called to compare the starve count of a
* given iowait with the given max starve count. The max starve
* count and the index will be updated if the iowait's start
* count is larger.
*/
static inline void iowait_starve_find_max(struct iowait *w, u8 *max,
uint idx, uint *max_idx)
{
if (w->starved_cnt > *max) {
*max = w->starved_cnt;
*max_idx = idx;
}
}
#endif #endif
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册