162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 or Linux-OpenIB
262306a36Sopenharmony_ci/* Copyright (c) 2015 - 2021 Intel Corporation */
362306a36Sopenharmony_ci#include "main.h"
462306a36Sopenharmony_ci
562306a36Sopenharmony_ci/**
662306a36Sopenharmony_ci * irdma_arp_table -manage arp table
762306a36Sopenharmony_ci * @rf: RDMA PCI function
862306a36Sopenharmony_ci * @ip_addr: ip address for device
962306a36Sopenharmony_ci * @ipv4: IPv4 flag
1062306a36Sopenharmony_ci * @mac_addr: mac address ptr
1162306a36Sopenharmony_ci * @action: modify, delete or add
1262306a36Sopenharmony_ci */
1362306a36Sopenharmony_ciint irdma_arp_table(struct irdma_pci_f *rf, u32 *ip_addr, bool ipv4,
1462306a36Sopenharmony_ci		    const u8 *mac_addr, u32 action)
1562306a36Sopenharmony_ci{
1662306a36Sopenharmony_ci	unsigned long flags;
1762306a36Sopenharmony_ci	int arp_index;
1862306a36Sopenharmony_ci	u32 ip[4] = {};
1962306a36Sopenharmony_ci
2062306a36Sopenharmony_ci	if (ipv4)
2162306a36Sopenharmony_ci		ip[0] = *ip_addr;
2262306a36Sopenharmony_ci	else
2362306a36Sopenharmony_ci		memcpy(ip, ip_addr, sizeof(ip));
2462306a36Sopenharmony_ci
2562306a36Sopenharmony_ci	spin_lock_irqsave(&rf->arp_lock, flags);
2662306a36Sopenharmony_ci	for (arp_index = 0; (u32)arp_index < rf->arp_table_size; arp_index++) {
2762306a36Sopenharmony_ci		if (!memcmp(rf->arp_table[arp_index].ip_addr, ip, sizeof(ip)))
2862306a36Sopenharmony_ci			break;
2962306a36Sopenharmony_ci	}
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_ci	switch (action) {
3262306a36Sopenharmony_ci	case IRDMA_ARP_ADD:
3362306a36Sopenharmony_ci		if (arp_index != rf->arp_table_size) {
3462306a36Sopenharmony_ci			arp_index = -1;
3562306a36Sopenharmony_ci			break;
3662306a36Sopenharmony_ci		}
3762306a36Sopenharmony_ci
3862306a36Sopenharmony_ci		arp_index = 0;
3962306a36Sopenharmony_ci		if (irdma_alloc_rsrc(rf, rf->allocated_arps, rf->arp_table_size,
4062306a36Sopenharmony_ci				     (u32 *)&arp_index, &rf->next_arp_index)) {
4162306a36Sopenharmony_ci			arp_index = -1;
4262306a36Sopenharmony_ci			break;
4362306a36Sopenharmony_ci		}
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_ci		memcpy(rf->arp_table[arp_index].ip_addr, ip,
4662306a36Sopenharmony_ci		       sizeof(rf->arp_table[arp_index].ip_addr));
4762306a36Sopenharmony_ci		ether_addr_copy(rf->arp_table[arp_index].mac_addr, mac_addr);
4862306a36Sopenharmony_ci		break;
4962306a36Sopenharmony_ci	case IRDMA_ARP_RESOLVE:
5062306a36Sopenharmony_ci		if (arp_index == rf->arp_table_size)
5162306a36Sopenharmony_ci			arp_index = -1;
5262306a36Sopenharmony_ci		break;
5362306a36Sopenharmony_ci	case IRDMA_ARP_DELETE:
5462306a36Sopenharmony_ci		if (arp_index == rf->arp_table_size) {
5562306a36Sopenharmony_ci			arp_index = -1;
5662306a36Sopenharmony_ci			break;
5762306a36Sopenharmony_ci		}
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_ci		memset(rf->arp_table[arp_index].ip_addr, 0,
6062306a36Sopenharmony_ci		       sizeof(rf->arp_table[arp_index].ip_addr));
6162306a36Sopenharmony_ci		eth_zero_addr(rf->arp_table[arp_index].mac_addr);
6262306a36Sopenharmony_ci		irdma_free_rsrc(rf, rf->allocated_arps, arp_index);
6362306a36Sopenharmony_ci		break;
6462306a36Sopenharmony_ci	default:
6562306a36Sopenharmony_ci		arp_index = -1;
6662306a36Sopenharmony_ci		break;
6762306a36Sopenharmony_ci	}
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_ci	spin_unlock_irqrestore(&rf->arp_lock, flags);
7062306a36Sopenharmony_ci	return arp_index;
7162306a36Sopenharmony_ci}
7262306a36Sopenharmony_ci
7362306a36Sopenharmony_ci/**
7462306a36Sopenharmony_ci * irdma_add_arp - add a new arp entry if needed
7562306a36Sopenharmony_ci * @rf: RDMA function
7662306a36Sopenharmony_ci * @ip: IP address
7762306a36Sopenharmony_ci * @ipv4: IPv4 flag
7862306a36Sopenharmony_ci * @mac: MAC address
7962306a36Sopenharmony_ci */
8062306a36Sopenharmony_ciint irdma_add_arp(struct irdma_pci_f *rf, u32 *ip, bool ipv4, const u8 *mac)
8162306a36Sopenharmony_ci{
8262306a36Sopenharmony_ci	int arpidx;
8362306a36Sopenharmony_ci
8462306a36Sopenharmony_ci	arpidx = irdma_arp_table(rf, &ip[0], ipv4, NULL, IRDMA_ARP_RESOLVE);
8562306a36Sopenharmony_ci	if (arpidx >= 0) {
8662306a36Sopenharmony_ci		if (ether_addr_equal(rf->arp_table[arpidx].mac_addr, mac))
8762306a36Sopenharmony_ci			return arpidx;
8862306a36Sopenharmony_ci
8962306a36Sopenharmony_ci		irdma_manage_arp_cache(rf, rf->arp_table[arpidx].mac_addr, ip,
9062306a36Sopenharmony_ci				       ipv4, IRDMA_ARP_DELETE);
9162306a36Sopenharmony_ci	}
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_ci	irdma_manage_arp_cache(rf, mac, ip, ipv4, IRDMA_ARP_ADD);
9462306a36Sopenharmony_ci
9562306a36Sopenharmony_ci	return irdma_arp_table(rf, ip, ipv4, NULL, IRDMA_ARP_RESOLVE);
9662306a36Sopenharmony_ci}
9762306a36Sopenharmony_ci
9862306a36Sopenharmony_ci/**
9962306a36Sopenharmony_ci * wr32 - write 32 bits to hw register
10062306a36Sopenharmony_ci * @hw: hardware information including registers
10162306a36Sopenharmony_ci * @reg: register offset
10262306a36Sopenharmony_ci * @val: value to write to register
10362306a36Sopenharmony_ci */
10462306a36Sopenharmony_ciinline void wr32(struct irdma_hw *hw, u32 reg, u32 val)
10562306a36Sopenharmony_ci{
10662306a36Sopenharmony_ci	writel(val, hw->hw_addr + reg);
10762306a36Sopenharmony_ci}
10862306a36Sopenharmony_ci
10962306a36Sopenharmony_ci/**
11062306a36Sopenharmony_ci * rd32 - read a 32 bit hw register
11162306a36Sopenharmony_ci * @hw: hardware information including registers
11262306a36Sopenharmony_ci * @reg: register offset
11362306a36Sopenharmony_ci *
11462306a36Sopenharmony_ci * Return value of register content
11562306a36Sopenharmony_ci */
11662306a36Sopenharmony_ciinline u32 rd32(struct irdma_hw *hw, u32 reg)
11762306a36Sopenharmony_ci{
11862306a36Sopenharmony_ci	return readl(hw->hw_addr + reg);
11962306a36Sopenharmony_ci}
12062306a36Sopenharmony_ci
12162306a36Sopenharmony_ci/**
12262306a36Sopenharmony_ci * rd64 - read a 64 bit hw register
12362306a36Sopenharmony_ci * @hw: hardware information including registers
12462306a36Sopenharmony_ci * @reg: register offset
12562306a36Sopenharmony_ci *
12662306a36Sopenharmony_ci * Return value of register content
12762306a36Sopenharmony_ci */
12862306a36Sopenharmony_ciinline u64 rd64(struct irdma_hw *hw, u32 reg)
12962306a36Sopenharmony_ci{
13062306a36Sopenharmony_ci	return readq(hw->hw_addr + reg);
13162306a36Sopenharmony_ci}
13262306a36Sopenharmony_ci
13362306a36Sopenharmony_cistatic void irdma_gid_change_event(struct ib_device *ibdev)
13462306a36Sopenharmony_ci{
13562306a36Sopenharmony_ci	struct ib_event ib_event;
13662306a36Sopenharmony_ci
13762306a36Sopenharmony_ci	ib_event.event = IB_EVENT_GID_CHANGE;
13862306a36Sopenharmony_ci	ib_event.device = ibdev;
13962306a36Sopenharmony_ci	ib_event.element.port_num = 1;
14062306a36Sopenharmony_ci	ib_dispatch_event(&ib_event);
14162306a36Sopenharmony_ci}
14262306a36Sopenharmony_ci
14362306a36Sopenharmony_ci/**
14462306a36Sopenharmony_ci * irdma_inetaddr_event - system notifier for ipv4 addr events
14562306a36Sopenharmony_ci * @notifier: not used
14662306a36Sopenharmony_ci * @event: event for notifier
14762306a36Sopenharmony_ci * @ptr: if address
14862306a36Sopenharmony_ci */
14962306a36Sopenharmony_ciint irdma_inetaddr_event(struct notifier_block *notifier, unsigned long event,
15062306a36Sopenharmony_ci			 void *ptr)
15162306a36Sopenharmony_ci{
15262306a36Sopenharmony_ci	struct in_ifaddr *ifa = ptr;
15362306a36Sopenharmony_ci	struct net_device *real_dev, *netdev = ifa->ifa_dev->dev;
15462306a36Sopenharmony_ci	struct irdma_device *iwdev;
15562306a36Sopenharmony_ci	struct ib_device *ibdev;
15662306a36Sopenharmony_ci	u32 local_ipaddr;
15762306a36Sopenharmony_ci
15862306a36Sopenharmony_ci	real_dev = rdma_vlan_dev_real_dev(netdev);
15962306a36Sopenharmony_ci	if (!real_dev)
16062306a36Sopenharmony_ci		real_dev = netdev;
16162306a36Sopenharmony_ci
16262306a36Sopenharmony_ci	ibdev = ib_device_get_by_netdev(real_dev, RDMA_DRIVER_IRDMA);
16362306a36Sopenharmony_ci	if (!ibdev)
16462306a36Sopenharmony_ci		return NOTIFY_DONE;
16562306a36Sopenharmony_ci
16662306a36Sopenharmony_ci	iwdev = to_iwdev(ibdev);
16762306a36Sopenharmony_ci	local_ipaddr = ntohl(ifa->ifa_address);
16862306a36Sopenharmony_ci	ibdev_dbg(&iwdev->ibdev,
16962306a36Sopenharmony_ci		  "DEV: netdev %p event %lu local_ip=%pI4 MAC=%pM\n", real_dev,
17062306a36Sopenharmony_ci		  event, &local_ipaddr, real_dev->dev_addr);
17162306a36Sopenharmony_ci	switch (event) {
17262306a36Sopenharmony_ci	case NETDEV_DOWN:
17362306a36Sopenharmony_ci		irdma_manage_arp_cache(iwdev->rf, real_dev->dev_addr,
17462306a36Sopenharmony_ci				       &local_ipaddr, true, IRDMA_ARP_DELETE);
17562306a36Sopenharmony_ci		irdma_if_notify(iwdev, real_dev, &local_ipaddr, true, false);
17662306a36Sopenharmony_ci		irdma_gid_change_event(&iwdev->ibdev);
17762306a36Sopenharmony_ci		break;
17862306a36Sopenharmony_ci	case NETDEV_UP:
17962306a36Sopenharmony_ci	case NETDEV_CHANGEADDR:
18062306a36Sopenharmony_ci		irdma_add_arp(iwdev->rf, &local_ipaddr, true, real_dev->dev_addr);
18162306a36Sopenharmony_ci		irdma_if_notify(iwdev, real_dev, &local_ipaddr, true, true);
18262306a36Sopenharmony_ci		irdma_gid_change_event(&iwdev->ibdev);
18362306a36Sopenharmony_ci		break;
18462306a36Sopenharmony_ci	default:
18562306a36Sopenharmony_ci		break;
18662306a36Sopenharmony_ci	}
18762306a36Sopenharmony_ci
18862306a36Sopenharmony_ci	ib_device_put(ibdev);
18962306a36Sopenharmony_ci
19062306a36Sopenharmony_ci	return NOTIFY_DONE;
19162306a36Sopenharmony_ci}
19262306a36Sopenharmony_ci
19362306a36Sopenharmony_ci/**
19462306a36Sopenharmony_ci * irdma_inet6addr_event - system notifier for ipv6 addr events
19562306a36Sopenharmony_ci * @notifier: not used
19662306a36Sopenharmony_ci * @event: event for notifier
19762306a36Sopenharmony_ci * @ptr: if address
19862306a36Sopenharmony_ci */
19962306a36Sopenharmony_ciint irdma_inet6addr_event(struct notifier_block *notifier, unsigned long event,
20062306a36Sopenharmony_ci			  void *ptr)
20162306a36Sopenharmony_ci{
20262306a36Sopenharmony_ci	struct inet6_ifaddr *ifa = ptr;
20362306a36Sopenharmony_ci	struct net_device *real_dev, *netdev = ifa->idev->dev;
20462306a36Sopenharmony_ci	struct irdma_device *iwdev;
20562306a36Sopenharmony_ci	struct ib_device *ibdev;
20662306a36Sopenharmony_ci	u32 local_ipaddr6[4];
20762306a36Sopenharmony_ci
20862306a36Sopenharmony_ci	real_dev = rdma_vlan_dev_real_dev(netdev);
20962306a36Sopenharmony_ci	if (!real_dev)
21062306a36Sopenharmony_ci		real_dev = netdev;
21162306a36Sopenharmony_ci
21262306a36Sopenharmony_ci	ibdev = ib_device_get_by_netdev(real_dev, RDMA_DRIVER_IRDMA);
21362306a36Sopenharmony_ci	if (!ibdev)
21462306a36Sopenharmony_ci		return NOTIFY_DONE;
21562306a36Sopenharmony_ci
21662306a36Sopenharmony_ci	iwdev = to_iwdev(ibdev);
21762306a36Sopenharmony_ci	irdma_copy_ip_ntohl(local_ipaddr6, ifa->addr.in6_u.u6_addr32);
21862306a36Sopenharmony_ci	ibdev_dbg(&iwdev->ibdev,
21962306a36Sopenharmony_ci		  "DEV: netdev %p event %lu local_ip=%pI6 MAC=%pM\n", real_dev,
22062306a36Sopenharmony_ci		  event, local_ipaddr6, real_dev->dev_addr);
22162306a36Sopenharmony_ci	switch (event) {
22262306a36Sopenharmony_ci	case NETDEV_DOWN:
22362306a36Sopenharmony_ci		irdma_manage_arp_cache(iwdev->rf, real_dev->dev_addr,
22462306a36Sopenharmony_ci				       local_ipaddr6, false, IRDMA_ARP_DELETE);
22562306a36Sopenharmony_ci		irdma_if_notify(iwdev, real_dev, local_ipaddr6, false, false);
22662306a36Sopenharmony_ci		irdma_gid_change_event(&iwdev->ibdev);
22762306a36Sopenharmony_ci		break;
22862306a36Sopenharmony_ci	case NETDEV_UP:
22962306a36Sopenharmony_ci	case NETDEV_CHANGEADDR:
23062306a36Sopenharmony_ci		irdma_add_arp(iwdev->rf, local_ipaddr6, false,
23162306a36Sopenharmony_ci			      real_dev->dev_addr);
23262306a36Sopenharmony_ci		irdma_if_notify(iwdev, real_dev, local_ipaddr6, false, true);
23362306a36Sopenharmony_ci		irdma_gid_change_event(&iwdev->ibdev);
23462306a36Sopenharmony_ci		break;
23562306a36Sopenharmony_ci	default:
23662306a36Sopenharmony_ci		break;
23762306a36Sopenharmony_ci	}
23862306a36Sopenharmony_ci
23962306a36Sopenharmony_ci	ib_device_put(ibdev);
24062306a36Sopenharmony_ci
24162306a36Sopenharmony_ci	return NOTIFY_DONE;
24262306a36Sopenharmony_ci}
24362306a36Sopenharmony_ci
24462306a36Sopenharmony_ci/**
24562306a36Sopenharmony_ci * irdma_net_event - system notifier for net events
24662306a36Sopenharmony_ci * @notifier: not used
24762306a36Sopenharmony_ci * @event: event for notifier
24862306a36Sopenharmony_ci * @ptr: neighbor
24962306a36Sopenharmony_ci */
25062306a36Sopenharmony_ciint irdma_net_event(struct notifier_block *notifier, unsigned long event,
25162306a36Sopenharmony_ci		    void *ptr)
25262306a36Sopenharmony_ci{
25362306a36Sopenharmony_ci	struct neighbour *neigh = ptr;
25462306a36Sopenharmony_ci	struct net_device *real_dev, *netdev = (struct net_device *)neigh->dev;
25562306a36Sopenharmony_ci	struct irdma_device *iwdev;
25662306a36Sopenharmony_ci	struct ib_device *ibdev;
25762306a36Sopenharmony_ci	__be32 *p;
25862306a36Sopenharmony_ci	u32 local_ipaddr[4] = {};
25962306a36Sopenharmony_ci	bool ipv4 = true;
26062306a36Sopenharmony_ci
26162306a36Sopenharmony_ci	switch (event) {
26262306a36Sopenharmony_ci	case NETEVENT_NEIGH_UPDATE:
26362306a36Sopenharmony_ci		real_dev = rdma_vlan_dev_real_dev(netdev);
26462306a36Sopenharmony_ci		if (!real_dev)
26562306a36Sopenharmony_ci			real_dev = netdev;
26662306a36Sopenharmony_ci		ibdev = ib_device_get_by_netdev(real_dev, RDMA_DRIVER_IRDMA);
26762306a36Sopenharmony_ci		if (!ibdev)
26862306a36Sopenharmony_ci			return NOTIFY_DONE;
26962306a36Sopenharmony_ci
27062306a36Sopenharmony_ci		iwdev = to_iwdev(ibdev);
27162306a36Sopenharmony_ci		p = (__be32 *)neigh->primary_key;
27262306a36Sopenharmony_ci		if (neigh->tbl->family == AF_INET6) {
27362306a36Sopenharmony_ci			ipv4 = false;
27462306a36Sopenharmony_ci			irdma_copy_ip_ntohl(local_ipaddr, p);
27562306a36Sopenharmony_ci		} else {
27662306a36Sopenharmony_ci			local_ipaddr[0] = ntohl(*p);
27762306a36Sopenharmony_ci		}
27862306a36Sopenharmony_ci
27962306a36Sopenharmony_ci		ibdev_dbg(&iwdev->ibdev,
28062306a36Sopenharmony_ci			  "DEV: netdev %p state %d local_ip=%pI4 MAC=%pM\n",
28162306a36Sopenharmony_ci			  iwdev->netdev, neigh->nud_state, local_ipaddr,
28262306a36Sopenharmony_ci			  neigh->ha);
28362306a36Sopenharmony_ci
28462306a36Sopenharmony_ci		if (neigh->nud_state & NUD_VALID)
28562306a36Sopenharmony_ci			irdma_add_arp(iwdev->rf, local_ipaddr, ipv4, neigh->ha);
28662306a36Sopenharmony_ci
28762306a36Sopenharmony_ci		else
28862306a36Sopenharmony_ci			irdma_manage_arp_cache(iwdev->rf, neigh->ha,
28962306a36Sopenharmony_ci					       local_ipaddr, ipv4,
29062306a36Sopenharmony_ci					       IRDMA_ARP_DELETE);
29162306a36Sopenharmony_ci		ib_device_put(ibdev);
29262306a36Sopenharmony_ci		break;
29362306a36Sopenharmony_ci	default:
29462306a36Sopenharmony_ci		break;
29562306a36Sopenharmony_ci	}
29662306a36Sopenharmony_ci
29762306a36Sopenharmony_ci	return NOTIFY_DONE;
29862306a36Sopenharmony_ci}
29962306a36Sopenharmony_ci
30062306a36Sopenharmony_ci/**
30162306a36Sopenharmony_ci * irdma_netdevice_event - system notifier for netdev events
30262306a36Sopenharmony_ci * @notifier: not used
30362306a36Sopenharmony_ci * @event: event for notifier
30462306a36Sopenharmony_ci * @ptr: netdev
30562306a36Sopenharmony_ci */
30662306a36Sopenharmony_ciint irdma_netdevice_event(struct notifier_block *notifier, unsigned long event,
30762306a36Sopenharmony_ci			  void *ptr)
30862306a36Sopenharmony_ci{
30962306a36Sopenharmony_ci	struct irdma_device *iwdev;
31062306a36Sopenharmony_ci	struct ib_device *ibdev;
31162306a36Sopenharmony_ci	struct net_device *netdev = netdev_notifier_info_to_dev(ptr);
31262306a36Sopenharmony_ci
31362306a36Sopenharmony_ci	ibdev = ib_device_get_by_netdev(netdev, RDMA_DRIVER_IRDMA);
31462306a36Sopenharmony_ci	if (!ibdev)
31562306a36Sopenharmony_ci		return NOTIFY_DONE;
31662306a36Sopenharmony_ci
31762306a36Sopenharmony_ci	iwdev = to_iwdev(ibdev);
31862306a36Sopenharmony_ci	iwdev->iw_status = 1;
31962306a36Sopenharmony_ci	switch (event) {
32062306a36Sopenharmony_ci	case NETDEV_DOWN:
32162306a36Sopenharmony_ci		iwdev->iw_status = 0;
32262306a36Sopenharmony_ci		fallthrough;
32362306a36Sopenharmony_ci	case NETDEV_UP:
32462306a36Sopenharmony_ci		irdma_port_ibevent(iwdev);
32562306a36Sopenharmony_ci		break;
32662306a36Sopenharmony_ci	default:
32762306a36Sopenharmony_ci		break;
32862306a36Sopenharmony_ci	}
32962306a36Sopenharmony_ci	ib_device_put(ibdev);
33062306a36Sopenharmony_ci
33162306a36Sopenharmony_ci	return NOTIFY_DONE;
33262306a36Sopenharmony_ci}
33362306a36Sopenharmony_ci
33462306a36Sopenharmony_ci/**
33562306a36Sopenharmony_ci * irdma_add_ipv6_addr - add ipv6 address to the hw arp table
33662306a36Sopenharmony_ci * @iwdev: irdma device
33762306a36Sopenharmony_ci */
33862306a36Sopenharmony_cistatic void irdma_add_ipv6_addr(struct irdma_device *iwdev)
33962306a36Sopenharmony_ci{
34062306a36Sopenharmony_ci	struct net_device *ip_dev;
34162306a36Sopenharmony_ci	struct inet6_dev *idev;
34262306a36Sopenharmony_ci	struct inet6_ifaddr *ifp, *tmp;
34362306a36Sopenharmony_ci	u32 local_ipaddr6[4];
34462306a36Sopenharmony_ci
34562306a36Sopenharmony_ci	rcu_read_lock();
34662306a36Sopenharmony_ci	for_each_netdev_rcu (&init_net, ip_dev) {
34762306a36Sopenharmony_ci		if (((rdma_vlan_dev_vlan_id(ip_dev) < 0xFFFF &&
34862306a36Sopenharmony_ci		      rdma_vlan_dev_real_dev(ip_dev) == iwdev->netdev) ||
34962306a36Sopenharmony_ci		      ip_dev == iwdev->netdev) &&
35062306a36Sopenharmony_ci		      (READ_ONCE(ip_dev->flags) & IFF_UP)) {
35162306a36Sopenharmony_ci			idev = __in6_dev_get(ip_dev);
35262306a36Sopenharmony_ci			if (!idev) {
35362306a36Sopenharmony_ci				ibdev_err(&iwdev->ibdev, "ipv6 inet device not found\n");
35462306a36Sopenharmony_ci				break;
35562306a36Sopenharmony_ci			}
35662306a36Sopenharmony_ci			list_for_each_entry_safe (ifp, tmp, &idev->addr_list,
35762306a36Sopenharmony_ci						  if_list) {
35862306a36Sopenharmony_ci				ibdev_dbg(&iwdev->ibdev,
35962306a36Sopenharmony_ci					  "INIT: IP=%pI6, vlan_id=%d, MAC=%pM\n",
36062306a36Sopenharmony_ci					  &ifp->addr,
36162306a36Sopenharmony_ci					  rdma_vlan_dev_vlan_id(ip_dev),
36262306a36Sopenharmony_ci					  ip_dev->dev_addr);
36362306a36Sopenharmony_ci
36462306a36Sopenharmony_ci				irdma_copy_ip_ntohl(local_ipaddr6,
36562306a36Sopenharmony_ci						    ifp->addr.in6_u.u6_addr32);
36662306a36Sopenharmony_ci				irdma_manage_arp_cache(iwdev->rf,
36762306a36Sopenharmony_ci						       ip_dev->dev_addr,
36862306a36Sopenharmony_ci						       local_ipaddr6, false,
36962306a36Sopenharmony_ci						       IRDMA_ARP_ADD);
37062306a36Sopenharmony_ci			}
37162306a36Sopenharmony_ci		}
37262306a36Sopenharmony_ci	}
37362306a36Sopenharmony_ci	rcu_read_unlock();
37462306a36Sopenharmony_ci}
37562306a36Sopenharmony_ci
37662306a36Sopenharmony_ci/**
37762306a36Sopenharmony_ci * irdma_add_ipv4_addr - add ipv4 address to the hw arp table
37862306a36Sopenharmony_ci * @iwdev: irdma device
37962306a36Sopenharmony_ci */
38062306a36Sopenharmony_cistatic void irdma_add_ipv4_addr(struct irdma_device *iwdev)
38162306a36Sopenharmony_ci{
38262306a36Sopenharmony_ci	struct net_device *dev;
38362306a36Sopenharmony_ci	struct in_device *idev;
38462306a36Sopenharmony_ci	u32 ip_addr;
38562306a36Sopenharmony_ci
38662306a36Sopenharmony_ci	rcu_read_lock();
38762306a36Sopenharmony_ci	for_each_netdev_rcu (&init_net, dev) {
38862306a36Sopenharmony_ci		if (((rdma_vlan_dev_vlan_id(dev) < 0xFFFF &&
38962306a36Sopenharmony_ci		      rdma_vlan_dev_real_dev(dev) == iwdev->netdev) ||
39062306a36Sopenharmony_ci		      dev == iwdev->netdev) && (READ_ONCE(dev->flags) & IFF_UP)) {
39162306a36Sopenharmony_ci			const struct in_ifaddr *ifa;
39262306a36Sopenharmony_ci
39362306a36Sopenharmony_ci			idev = __in_dev_get_rcu(dev);
39462306a36Sopenharmony_ci			if (!idev)
39562306a36Sopenharmony_ci				continue;
39662306a36Sopenharmony_ci
39762306a36Sopenharmony_ci			in_dev_for_each_ifa_rcu(ifa, idev) {
39862306a36Sopenharmony_ci				ibdev_dbg(&iwdev->ibdev, "CM: IP=%pI4, vlan_id=%d, MAC=%pM\n",
39962306a36Sopenharmony_ci					  &ifa->ifa_address, rdma_vlan_dev_vlan_id(dev),
40062306a36Sopenharmony_ci					  dev->dev_addr);
40162306a36Sopenharmony_ci
40262306a36Sopenharmony_ci				ip_addr = ntohl(ifa->ifa_address);
40362306a36Sopenharmony_ci				irdma_manage_arp_cache(iwdev->rf, dev->dev_addr,
40462306a36Sopenharmony_ci						       &ip_addr, true,
40562306a36Sopenharmony_ci						       IRDMA_ARP_ADD);
40662306a36Sopenharmony_ci			}
40762306a36Sopenharmony_ci		}
40862306a36Sopenharmony_ci	}
40962306a36Sopenharmony_ci	rcu_read_unlock();
41062306a36Sopenharmony_ci}
41162306a36Sopenharmony_ci
41262306a36Sopenharmony_ci/**
41362306a36Sopenharmony_ci * irdma_add_ip - add ip addresses
41462306a36Sopenharmony_ci * @iwdev: irdma device
41562306a36Sopenharmony_ci *
41662306a36Sopenharmony_ci * Add ipv4/ipv6 addresses to the arp cache
41762306a36Sopenharmony_ci */
41862306a36Sopenharmony_civoid irdma_add_ip(struct irdma_device *iwdev)
41962306a36Sopenharmony_ci{
42062306a36Sopenharmony_ci	irdma_add_ipv4_addr(iwdev);
42162306a36Sopenharmony_ci	irdma_add_ipv6_addr(iwdev);
42262306a36Sopenharmony_ci}
42362306a36Sopenharmony_ci
42462306a36Sopenharmony_ci/**
42562306a36Sopenharmony_ci * irdma_alloc_and_get_cqp_request - get cqp struct
42662306a36Sopenharmony_ci * @cqp: device cqp ptr
42762306a36Sopenharmony_ci * @wait: cqp to be used in wait mode
42862306a36Sopenharmony_ci */
42962306a36Sopenharmony_cistruct irdma_cqp_request *irdma_alloc_and_get_cqp_request(struct irdma_cqp *cqp,
43062306a36Sopenharmony_ci							  bool wait)
43162306a36Sopenharmony_ci{
43262306a36Sopenharmony_ci	struct irdma_cqp_request *cqp_request = NULL;
43362306a36Sopenharmony_ci	unsigned long flags;
43462306a36Sopenharmony_ci
43562306a36Sopenharmony_ci	spin_lock_irqsave(&cqp->req_lock, flags);
43662306a36Sopenharmony_ci	if (!list_empty(&cqp->cqp_avail_reqs)) {
43762306a36Sopenharmony_ci		cqp_request = list_first_entry(&cqp->cqp_avail_reqs,
43862306a36Sopenharmony_ci					       struct irdma_cqp_request, list);
43962306a36Sopenharmony_ci		list_del_init(&cqp_request->list);
44062306a36Sopenharmony_ci	}
44162306a36Sopenharmony_ci	spin_unlock_irqrestore(&cqp->req_lock, flags);
44262306a36Sopenharmony_ci	if (!cqp_request) {
44362306a36Sopenharmony_ci		cqp_request = kzalloc(sizeof(*cqp_request), GFP_ATOMIC);
44462306a36Sopenharmony_ci		if (cqp_request) {
44562306a36Sopenharmony_ci			cqp_request->dynamic = true;
44662306a36Sopenharmony_ci			if (wait)
44762306a36Sopenharmony_ci				init_waitqueue_head(&cqp_request->waitq);
44862306a36Sopenharmony_ci		}
44962306a36Sopenharmony_ci	}
45062306a36Sopenharmony_ci	if (!cqp_request) {
45162306a36Sopenharmony_ci		ibdev_dbg(to_ibdev(cqp->sc_cqp.dev), "ERR: CQP Request Fail: No Memory");
45262306a36Sopenharmony_ci		return NULL;
45362306a36Sopenharmony_ci	}
45462306a36Sopenharmony_ci
45562306a36Sopenharmony_ci	cqp_request->waiting = wait;
45662306a36Sopenharmony_ci	refcount_set(&cqp_request->refcnt, 1);
45762306a36Sopenharmony_ci	memset(&cqp_request->compl_info, 0, sizeof(cqp_request->compl_info));
45862306a36Sopenharmony_ci
45962306a36Sopenharmony_ci	return cqp_request;
46062306a36Sopenharmony_ci}
46162306a36Sopenharmony_ci
46262306a36Sopenharmony_ci/**
46362306a36Sopenharmony_ci * irdma_get_cqp_request - increase refcount for cqp_request
46462306a36Sopenharmony_ci * @cqp_request: pointer to cqp_request instance
46562306a36Sopenharmony_ci */
46662306a36Sopenharmony_cistatic inline void irdma_get_cqp_request(struct irdma_cqp_request *cqp_request)
46762306a36Sopenharmony_ci{
46862306a36Sopenharmony_ci	refcount_inc(&cqp_request->refcnt);
46962306a36Sopenharmony_ci}
47062306a36Sopenharmony_ci
47162306a36Sopenharmony_ci/**
47262306a36Sopenharmony_ci * irdma_free_cqp_request - free cqp request
47362306a36Sopenharmony_ci * @cqp: cqp ptr
47462306a36Sopenharmony_ci * @cqp_request: to be put back in cqp list
47562306a36Sopenharmony_ci */
47662306a36Sopenharmony_civoid irdma_free_cqp_request(struct irdma_cqp *cqp,
47762306a36Sopenharmony_ci			    struct irdma_cqp_request *cqp_request)
47862306a36Sopenharmony_ci{
47962306a36Sopenharmony_ci	unsigned long flags;
48062306a36Sopenharmony_ci
48162306a36Sopenharmony_ci	if (cqp_request->dynamic) {
48262306a36Sopenharmony_ci		kfree(cqp_request);
48362306a36Sopenharmony_ci	} else {
48462306a36Sopenharmony_ci		WRITE_ONCE(cqp_request->request_done, false);
48562306a36Sopenharmony_ci		cqp_request->callback_fcn = NULL;
48662306a36Sopenharmony_ci		cqp_request->waiting = false;
48762306a36Sopenharmony_ci
48862306a36Sopenharmony_ci		spin_lock_irqsave(&cqp->req_lock, flags);
48962306a36Sopenharmony_ci		list_add_tail(&cqp_request->list, &cqp->cqp_avail_reqs);
49062306a36Sopenharmony_ci		spin_unlock_irqrestore(&cqp->req_lock, flags);
49162306a36Sopenharmony_ci	}
49262306a36Sopenharmony_ci	wake_up(&cqp->remove_wq);
49362306a36Sopenharmony_ci}
49462306a36Sopenharmony_ci
49562306a36Sopenharmony_ci/**
49662306a36Sopenharmony_ci * irdma_put_cqp_request - dec ref count and free if 0
49762306a36Sopenharmony_ci * @cqp: cqp ptr
49862306a36Sopenharmony_ci * @cqp_request: to be put back in cqp list
49962306a36Sopenharmony_ci */
50062306a36Sopenharmony_civoid irdma_put_cqp_request(struct irdma_cqp *cqp,
50162306a36Sopenharmony_ci			   struct irdma_cqp_request *cqp_request)
50262306a36Sopenharmony_ci{
50362306a36Sopenharmony_ci	if (refcount_dec_and_test(&cqp_request->refcnt))
50462306a36Sopenharmony_ci		irdma_free_cqp_request(cqp, cqp_request);
50562306a36Sopenharmony_ci}
50662306a36Sopenharmony_ci
50762306a36Sopenharmony_ci/**
50862306a36Sopenharmony_ci * irdma_free_pending_cqp_request -free pending cqp request objs
50962306a36Sopenharmony_ci * @cqp: cqp ptr
51062306a36Sopenharmony_ci * @cqp_request: to be put back in cqp list
51162306a36Sopenharmony_ci */
51262306a36Sopenharmony_cistatic void
51362306a36Sopenharmony_ciirdma_free_pending_cqp_request(struct irdma_cqp *cqp,
51462306a36Sopenharmony_ci			       struct irdma_cqp_request *cqp_request)
51562306a36Sopenharmony_ci{
51662306a36Sopenharmony_ci	if (cqp_request->waiting) {
51762306a36Sopenharmony_ci		cqp_request->compl_info.error = true;
51862306a36Sopenharmony_ci		WRITE_ONCE(cqp_request->request_done, true);
51962306a36Sopenharmony_ci		wake_up(&cqp_request->waitq);
52062306a36Sopenharmony_ci	}
52162306a36Sopenharmony_ci	wait_event_timeout(cqp->remove_wq,
52262306a36Sopenharmony_ci			   refcount_read(&cqp_request->refcnt) == 1, 1000);
52362306a36Sopenharmony_ci	irdma_put_cqp_request(cqp, cqp_request);
52462306a36Sopenharmony_ci}
52562306a36Sopenharmony_ci
52662306a36Sopenharmony_ci/**
52762306a36Sopenharmony_ci * irdma_cleanup_pending_cqp_op - clean-up cqp with no
52862306a36Sopenharmony_ci * completions
52962306a36Sopenharmony_ci * @rf: RDMA PCI function
53062306a36Sopenharmony_ci */
53162306a36Sopenharmony_civoid irdma_cleanup_pending_cqp_op(struct irdma_pci_f *rf)
53262306a36Sopenharmony_ci{
53362306a36Sopenharmony_ci	struct irdma_sc_dev *dev = &rf->sc_dev;
53462306a36Sopenharmony_ci	struct irdma_cqp *cqp = &rf->cqp;
53562306a36Sopenharmony_ci	struct irdma_cqp_request *cqp_request = NULL;
53662306a36Sopenharmony_ci	struct cqp_cmds_info *pcmdinfo = NULL;
53762306a36Sopenharmony_ci	u32 i, pending_work, wqe_idx;
53862306a36Sopenharmony_ci
53962306a36Sopenharmony_ci	pending_work = IRDMA_RING_USED_QUANTA(cqp->sc_cqp.sq_ring);
54062306a36Sopenharmony_ci	wqe_idx = IRDMA_RING_CURRENT_TAIL(cqp->sc_cqp.sq_ring);
54162306a36Sopenharmony_ci	for (i = 0; i < pending_work; i++) {
54262306a36Sopenharmony_ci		cqp_request = (struct irdma_cqp_request *)(unsigned long)
54362306a36Sopenharmony_ci				      cqp->scratch_array[wqe_idx];
54462306a36Sopenharmony_ci		if (cqp_request)
54562306a36Sopenharmony_ci			irdma_free_pending_cqp_request(cqp, cqp_request);
54662306a36Sopenharmony_ci		wqe_idx = (wqe_idx + 1) % IRDMA_RING_SIZE(cqp->sc_cqp.sq_ring);
54762306a36Sopenharmony_ci	}
54862306a36Sopenharmony_ci
54962306a36Sopenharmony_ci	while (!list_empty(&dev->cqp_cmd_head)) {
55062306a36Sopenharmony_ci		pcmdinfo = irdma_remove_cqp_head(dev);
55162306a36Sopenharmony_ci		cqp_request =
55262306a36Sopenharmony_ci			container_of(pcmdinfo, struct irdma_cqp_request, info);
55362306a36Sopenharmony_ci		if (cqp_request)
55462306a36Sopenharmony_ci			irdma_free_pending_cqp_request(cqp, cqp_request);
55562306a36Sopenharmony_ci	}
55662306a36Sopenharmony_ci}
55762306a36Sopenharmony_ci
55862306a36Sopenharmony_ci/**
55962306a36Sopenharmony_ci * irdma_wait_event - wait for completion
56062306a36Sopenharmony_ci * @rf: RDMA PCI function
56162306a36Sopenharmony_ci * @cqp_request: cqp request to wait
56262306a36Sopenharmony_ci */
56362306a36Sopenharmony_cistatic int irdma_wait_event(struct irdma_pci_f *rf,
56462306a36Sopenharmony_ci			    struct irdma_cqp_request *cqp_request)
56562306a36Sopenharmony_ci{
56662306a36Sopenharmony_ci	struct irdma_cqp_timeout cqp_timeout = {};
56762306a36Sopenharmony_ci	bool cqp_error = false;
56862306a36Sopenharmony_ci	int err_code = 0;
56962306a36Sopenharmony_ci
57062306a36Sopenharmony_ci	cqp_timeout.compl_cqp_cmds = atomic64_read(&rf->sc_dev.cqp->completed_ops);
57162306a36Sopenharmony_ci	do {
57262306a36Sopenharmony_ci		irdma_cqp_ce_handler(rf, &rf->ccq.sc_cq);
57362306a36Sopenharmony_ci		if (wait_event_timeout(cqp_request->waitq,
57462306a36Sopenharmony_ci				       READ_ONCE(cqp_request->request_done),
57562306a36Sopenharmony_ci				       msecs_to_jiffies(CQP_COMPL_WAIT_TIME_MS)))
57662306a36Sopenharmony_ci			break;
57762306a36Sopenharmony_ci
57862306a36Sopenharmony_ci		irdma_check_cqp_progress(&cqp_timeout, &rf->sc_dev);
57962306a36Sopenharmony_ci
58062306a36Sopenharmony_ci		if (cqp_timeout.count < CQP_TIMEOUT_THRESHOLD)
58162306a36Sopenharmony_ci			continue;
58262306a36Sopenharmony_ci
58362306a36Sopenharmony_ci		if (!rf->reset) {
58462306a36Sopenharmony_ci			rf->reset = true;
58562306a36Sopenharmony_ci			rf->gen_ops.request_reset(rf);
58662306a36Sopenharmony_ci		}
58762306a36Sopenharmony_ci		return -ETIMEDOUT;
58862306a36Sopenharmony_ci	} while (1);
58962306a36Sopenharmony_ci
59062306a36Sopenharmony_ci	cqp_error = cqp_request->compl_info.error;
59162306a36Sopenharmony_ci	if (cqp_error) {
59262306a36Sopenharmony_ci		err_code = -EIO;
59362306a36Sopenharmony_ci		if (cqp_request->compl_info.maj_err_code == 0xFFFF) {
59462306a36Sopenharmony_ci			if (cqp_request->compl_info.min_err_code == 0x8002)
59562306a36Sopenharmony_ci				err_code = -EBUSY;
59662306a36Sopenharmony_ci			else if (cqp_request->compl_info.min_err_code == 0x8029) {
59762306a36Sopenharmony_ci				if (!rf->reset) {
59862306a36Sopenharmony_ci					rf->reset = true;
59962306a36Sopenharmony_ci					rf->gen_ops.request_reset(rf);
60062306a36Sopenharmony_ci				}
60162306a36Sopenharmony_ci			}
60262306a36Sopenharmony_ci		}
60362306a36Sopenharmony_ci	}
60462306a36Sopenharmony_ci
60562306a36Sopenharmony_ci	return err_code;
60662306a36Sopenharmony_ci}
60762306a36Sopenharmony_ci
60862306a36Sopenharmony_cistatic const char *const irdma_cqp_cmd_names[IRDMA_MAX_CQP_OPS] = {
60962306a36Sopenharmony_ci	[IRDMA_OP_CEQ_DESTROY] = "Destroy CEQ Cmd",
61062306a36Sopenharmony_ci	[IRDMA_OP_AEQ_DESTROY] = "Destroy AEQ Cmd",
61162306a36Sopenharmony_ci	[IRDMA_OP_DELETE_ARP_CACHE_ENTRY] = "Delete ARP Cache Cmd",
61262306a36Sopenharmony_ci	[IRDMA_OP_MANAGE_APBVT_ENTRY] = "Manage APBV Table Entry Cmd",
61362306a36Sopenharmony_ci	[IRDMA_OP_CEQ_CREATE] = "CEQ Create Cmd",
61462306a36Sopenharmony_ci	[IRDMA_OP_AEQ_CREATE] = "AEQ Destroy Cmd",
61562306a36Sopenharmony_ci	[IRDMA_OP_MANAGE_QHASH_TABLE_ENTRY] = "Manage Quad Hash Table Entry Cmd",
61662306a36Sopenharmony_ci	[IRDMA_OP_QP_MODIFY] = "Modify QP Cmd",
61762306a36Sopenharmony_ci	[IRDMA_OP_QP_UPLOAD_CONTEXT] = "Upload Context Cmd",
61862306a36Sopenharmony_ci	[IRDMA_OP_CQ_CREATE] = "Create CQ Cmd",
61962306a36Sopenharmony_ci	[IRDMA_OP_CQ_DESTROY] = "Destroy CQ Cmd",
62062306a36Sopenharmony_ci	[IRDMA_OP_QP_CREATE] = "Create QP Cmd",
62162306a36Sopenharmony_ci	[IRDMA_OP_QP_DESTROY] = "Destroy QP Cmd",
62262306a36Sopenharmony_ci	[IRDMA_OP_ALLOC_STAG] = "Allocate STag Cmd",
62362306a36Sopenharmony_ci	[IRDMA_OP_MR_REG_NON_SHARED] = "Register Non-Shared MR Cmd",
62462306a36Sopenharmony_ci	[IRDMA_OP_DEALLOC_STAG] = "Deallocate STag Cmd",
62562306a36Sopenharmony_ci	[IRDMA_OP_MW_ALLOC] = "Allocate Memory Window Cmd",
62662306a36Sopenharmony_ci	[IRDMA_OP_QP_FLUSH_WQES] = "Flush QP Cmd",
62762306a36Sopenharmony_ci	[IRDMA_OP_ADD_ARP_CACHE_ENTRY] = "Add ARP Cache Cmd",
62862306a36Sopenharmony_ci	[IRDMA_OP_MANAGE_PUSH_PAGE] = "Manage Push Page Cmd",
62962306a36Sopenharmony_ci	[IRDMA_OP_UPDATE_PE_SDS] = "Update PE SDs Cmd",
63062306a36Sopenharmony_ci	[IRDMA_OP_MANAGE_HMC_PM_FUNC_TABLE] = "Manage HMC PM Function Table Cmd",
63162306a36Sopenharmony_ci	[IRDMA_OP_SUSPEND] = "Suspend QP Cmd",
63262306a36Sopenharmony_ci	[IRDMA_OP_RESUME] = "Resume QP Cmd",
63362306a36Sopenharmony_ci	[IRDMA_OP_MANAGE_VF_PBLE_BP] = "Manage VF PBLE Backing Pages Cmd",
63462306a36Sopenharmony_ci	[IRDMA_OP_QUERY_FPM_VAL] = "Query FPM Values Cmd",
63562306a36Sopenharmony_ci	[IRDMA_OP_COMMIT_FPM_VAL] = "Commit FPM Values Cmd",
63662306a36Sopenharmony_ci	[IRDMA_OP_AH_CREATE] = "Create Address Handle Cmd",
63762306a36Sopenharmony_ci	[IRDMA_OP_AH_MODIFY] = "Modify Address Handle Cmd",
63862306a36Sopenharmony_ci	[IRDMA_OP_AH_DESTROY] = "Destroy Address Handle Cmd",
63962306a36Sopenharmony_ci	[IRDMA_OP_MC_CREATE] = "Create Multicast Group Cmd",
64062306a36Sopenharmony_ci	[IRDMA_OP_MC_DESTROY] = "Destroy Multicast Group Cmd",
64162306a36Sopenharmony_ci	[IRDMA_OP_MC_MODIFY] = "Modify Multicast Group Cmd",
64262306a36Sopenharmony_ci	[IRDMA_OP_STATS_ALLOCATE] = "Add Statistics Instance Cmd",
64362306a36Sopenharmony_ci	[IRDMA_OP_STATS_FREE] = "Free Statistics Instance Cmd",
64462306a36Sopenharmony_ci	[IRDMA_OP_STATS_GATHER] = "Gather Statistics Cmd",
64562306a36Sopenharmony_ci	[IRDMA_OP_WS_ADD_NODE] = "Add Work Scheduler Node Cmd",
64662306a36Sopenharmony_ci	[IRDMA_OP_WS_MODIFY_NODE] = "Modify Work Scheduler Node Cmd",
64762306a36Sopenharmony_ci	[IRDMA_OP_WS_DELETE_NODE] = "Delete Work Scheduler Node Cmd",
64862306a36Sopenharmony_ci	[IRDMA_OP_SET_UP_MAP] = "Set UP-UP Mapping Cmd",
64962306a36Sopenharmony_ci	[IRDMA_OP_GEN_AE] = "Generate AE Cmd",
65062306a36Sopenharmony_ci	[IRDMA_OP_QUERY_RDMA_FEATURES] = "RDMA Get Features Cmd",
65162306a36Sopenharmony_ci	[IRDMA_OP_ALLOC_LOCAL_MAC_ENTRY] = "Allocate Local MAC Entry Cmd",
65262306a36Sopenharmony_ci	[IRDMA_OP_ADD_LOCAL_MAC_ENTRY] = "Add Local MAC Entry Cmd",
65362306a36Sopenharmony_ci	[IRDMA_OP_DELETE_LOCAL_MAC_ENTRY] = "Delete Local MAC Entry Cmd",
65462306a36Sopenharmony_ci	[IRDMA_OP_CQ_MODIFY] = "CQ Modify Cmd",
65562306a36Sopenharmony_ci};
65662306a36Sopenharmony_ci
65762306a36Sopenharmony_cistatic const struct irdma_cqp_err_info irdma_noncrit_err_list[] = {
65862306a36Sopenharmony_ci	{0xffff, 0x8002, "Invalid State"},
65962306a36Sopenharmony_ci	{0xffff, 0x8006, "Flush No Wqe Pending"},
66062306a36Sopenharmony_ci	{0xffff, 0x8007, "Modify QP Bad Close"},
66162306a36Sopenharmony_ci	{0xffff, 0x8009, "LLP Closed"},
66262306a36Sopenharmony_ci	{0xffff, 0x800a, "Reset Not Sent"}
66362306a36Sopenharmony_ci};
66462306a36Sopenharmony_ci
66562306a36Sopenharmony_ci/**
66662306a36Sopenharmony_ci * irdma_cqp_crit_err - check if CQP error is critical
66762306a36Sopenharmony_ci * @dev: pointer to dev structure
66862306a36Sopenharmony_ci * @cqp_cmd: code for last CQP operation
66962306a36Sopenharmony_ci * @maj_err_code: major error code
67062306a36Sopenharmony_ci * @min_err_code: minot error code
67162306a36Sopenharmony_ci */
67262306a36Sopenharmony_cibool irdma_cqp_crit_err(struct irdma_sc_dev *dev, u8 cqp_cmd,
67362306a36Sopenharmony_ci			u16 maj_err_code, u16 min_err_code)
67462306a36Sopenharmony_ci{
67562306a36Sopenharmony_ci	int i;
67662306a36Sopenharmony_ci
67762306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(irdma_noncrit_err_list); ++i) {
67862306a36Sopenharmony_ci		if (maj_err_code == irdma_noncrit_err_list[i].maj &&
67962306a36Sopenharmony_ci		    min_err_code == irdma_noncrit_err_list[i].min) {
68062306a36Sopenharmony_ci			ibdev_dbg(to_ibdev(dev),
68162306a36Sopenharmony_ci				  "CQP: [%s Error][%s] maj=0x%x min=0x%x\n",
68262306a36Sopenharmony_ci				  irdma_noncrit_err_list[i].desc,
68362306a36Sopenharmony_ci				  irdma_cqp_cmd_names[cqp_cmd], maj_err_code,
68462306a36Sopenharmony_ci				  min_err_code);
68562306a36Sopenharmony_ci			return false;
68662306a36Sopenharmony_ci		}
68762306a36Sopenharmony_ci	}
68862306a36Sopenharmony_ci	return true;
68962306a36Sopenharmony_ci}
69062306a36Sopenharmony_ci
69162306a36Sopenharmony_ci/**
69262306a36Sopenharmony_ci * irdma_handle_cqp_op - process cqp command
69362306a36Sopenharmony_ci * @rf: RDMA PCI function
69462306a36Sopenharmony_ci * @cqp_request: cqp request to process
69562306a36Sopenharmony_ci */
69662306a36Sopenharmony_ciint irdma_handle_cqp_op(struct irdma_pci_f *rf,
69762306a36Sopenharmony_ci			struct irdma_cqp_request *cqp_request)
69862306a36Sopenharmony_ci{
69962306a36Sopenharmony_ci	struct irdma_sc_dev *dev = &rf->sc_dev;
70062306a36Sopenharmony_ci	struct cqp_cmds_info *info = &cqp_request->info;
70162306a36Sopenharmony_ci	int status;
70262306a36Sopenharmony_ci	bool put_cqp_request = true;
70362306a36Sopenharmony_ci
70462306a36Sopenharmony_ci	if (rf->reset)
70562306a36Sopenharmony_ci		return -EBUSY;
70662306a36Sopenharmony_ci
70762306a36Sopenharmony_ci	irdma_get_cqp_request(cqp_request);
70862306a36Sopenharmony_ci	status = irdma_process_cqp_cmd(dev, info);
70962306a36Sopenharmony_ci	if (status)
71062306a36Sopenharmony_ci		goto err;
71162306a36Sopenharmony_ci
71262306a36Sopenharmony_ci	if (cqp_request->waiting) {
71362306a36Sopenharmony_ci		put_cqp_request = false;
71462306a36Sopenharmony_ci		status = irdma_wait_event(rf, cqp_request);
71562306a36Sopenharmony_ci		if (status)
71662306a36Sopenharmony_ci			goto err;
71762306a36Sopenharmony_ci	}
71862306a36Sopenharmony_ci
71962306a36Sopenharmony_ci	return 0;
72062306a36Sopenharmony_ci
72162306a36Sopenharmony_cierr:
72262306a36Sopenharmony_ci	if (irdma_cqp_crit_err(dev, info->cqp_cmd,
72362306a36Sopenharmony_ci			       cqp_request->compl_info.maj_err_code,
72462306a36Sopenharmony_ci			       cqp_request->compl_info.min_err_code))
72562306a36Sopenharmony_ci		ibdev_err(&rf->iwdev->ibdev,
72662306a36Sopenharmony_ci			  "[%s Error][op_code=%d] status=%d waiting=%d completion_err=%d maj=0x%x min=0x%x\n",
72762306a36Sopenharmony_ci			  irdma_cqp_cmd_names[info->cqp_cmd], info->cqp_cmd, status, cqp_request->waiting,
72862306a36Sopenharmony_ci			  cqp_request->compl_info.error, cqp_request->compl_info.maj_err_code,
72962306a36Sopenharmony_ci			  cqp_request->compl_info.min_err_code);
73062306a36Sopenharmony_ci
73162306a36Sopenharmony_ci	if (put_cqp_request)
73262306a36Sopenharmony_ci		irdma_put_cqp_request(&rf->cqp, cqp_request);
73362306a36Sopenharmony_ci
73462306a36Sopenharmony_ci	return status;
73562306a36Sopenharmony_ci}
73662306a36Sopenharmony_ci
73762306a36Sopenharmony_civoid irdma_qp_add_ref(struct ib_qp *ibqp)
73862306a36Sopenharmony_ci{
73962306a36Sopenharmony_ci	struct irdma_qp *iwqp = (struct irdma_qp *)ibqp;
74062306a36Sopenharmony_ci
74162306a36Sopenharmony_ci	refcount_inc(&iwqp->refcnt);
74262306a36Sopenharmony_ci}
74362306a36Sopenharmony_ci
74462306a36Sopenharmony_civoid irdma_qp_rem_ref(struct ib_qp *ibqp)
74562306a36Sopenharmony_ci{
74662306a36Sopenharmony_ci	struct irdma_qp *iwqp = to_iwqp(ibqp);
74762306a36Sopenharmony_ci	struct irdma_device *iwdev = iwqp->iwdev;
74862306a36Sopenharmony_ci	u32 qp_num;
74962306a36Sopenharmony_ci	unsigned long flags;
75062306a36Sopenharmony_ci
75162306a36Sopenharmony_ci	spin_lock_irqsave(&iwdev->rf->qptable_lock, flags);
75262306a36Sopenharmony_ci	if (!refcount_dec_and_test(&iwqp->refcnt)) {
75362306a36Sopenharmony_ci		spin_unlock_irqrestore(&iwdev->rf->qptable_lock, flags);
75462306a36Sopenharmony_ci		return;
75562306a36Sopenharmony_ci	}
75662306a36Sopenharmony_ci
75762306a36Sopenharmony_ci	qp_num = iwqp->ibqp.qp_num;
75862306a36Sopenharmony_ci	iwdev->rf->qp_table[qp_num] = NULL;
75962306a36Sopenharmony_ci	spin_unlock_irqrestore(&iwdev->rf->qptable_lock, flags);
76062306a36Sopenharmony_ci	complete(&iwqp->free_qp);
76162306a36Sopenharmony_ci}
76262306a36Sopenharmony_ci
76362306a36Sopenharmony_civoid irdma_cq_add_ref(struct ib_cq *ibcq)
76462306a36Sopenharmony_ci{
76562306a36Sopenharmony_ci	struct irdma_cq *iwcq = to_iwcq(ibcq);
76662306a36Sopenharmony_ci
76762306a36Sopenharmony_ci	refcount_inc(&iwcq->refcnt);
76862306a36Sopenharmony_ci}
76962306a36Sopenharmony_ci
77062306a36Sopenharmony_civoid irdma_cq_rem_ref(struct ib_cq *ibcq)
77162306a36Sopenharmony_ci{
77262306a36Sopenharmony_ci	struct ib_device *ibdev = ibcq->device;
77362306a36Sopenharmony_ci	struct irdma_device *iwdev = to_iwdev(ibdev);
77462306a36Sopenharmony_ci	struct irdma_cq *iwcq = to_iwcq(ibcq);
77562306a36Sopenharmony_ci	unsigned long flags;
77662306a36Sopenharmony_ci
77762306a36Sopenharmony_ci	spin_lock_irqsave(&iwdev->rf->cqtable_lock, flags);
77862306a36Sopenharmony_ci	if (!refcount_dec_and_test(&iwcq->refcnt)) {
77962306a36Sopenharmony_ci		spin_unlock_irqrestore(&iwdev->rf->cqtable_lock, flags);
78062306a36Sopenharmony_ci		return;
78162306a36Sopenharmony_ci	}
78262306a36Sopenharmony_ci
78362306a36Sopenharmony_ci	iwdev->rf->cq_table[iwcq->cq_num] = NULL;
78462306a36Sopenharmony_ci	spin_unlock_irqrestore(&iwdev->rf->cqtable_lock, flags);
78562306a36Sopenharmony_ci	complete(&iwcq->free_cq);
78662306a36Sopenharmony_ci}
78762306a36Sopenharmony_ci
78862306a36Sopenharmony_cistruct ib_device *to_ibdev(struct irdma_sc_dev *dev)
78962306a36Sopenharmony_ci{
79062306a36Sopenharmony_ci	return &(container_of(dev, struct irdma_pci_f, sc_dev))->iwdev->ibdev;
79162306a36Sopenharmony_ci}
79262306a36Sopenharmony_ci
79362306a36Sopenharmony_ci/**
79462306a36Sopenharmony_ci * irdma_get_qp - get qp address
79562306a36Sopenharmony_ci * @device: iwarp device
79662306a36Sopenharmony_ci * @qpn: qp number
79762306a36Sopenharmony_ci */
79862306a36Sopenharmony_cistruct ib_qp *irdma_get_qp(struct ib_device *device, int qpn)
79962306a36Sopenharmony_ci{
80062306a36Sopenharmony_ci	struct irdma_device *iwdev = to_iwdev(device);
80162306a36Sopenharmony_ci
80262306a36Sopenharmony_ci	if (qpn < IW_FIRST_QPN || qpn >= iwdev->rf->max_qp)
80362306a36Sopenharmony_ci		return NULL;
80462306a36Sopenharmony_ci
80562306a36Sopenharmony_ci	return &iwdev->rf->qp_table[qpn]->ibqp;
80662306a36Sopenharmony_ci}
80762306a36Sopenharmony_ci
80862306a36Sopenharmony_ci/**
80962306a36Sopenharmony_ci * irdma_remove_cqp_head - return head entry and remove
81062306a36Sopenharmony_ci * @dev: device
81162306a36Sopenharmony_ci */
81262306a36Sopenharmony_civoid *irdma_remove_cqp_head(struct irdma_sc_dev *dev)
81362306a36Sopenharmony_ci{
81462306a36Sopenharmony_ci	struct list_head *entry;
81562306a36Sopenharmony_ci	struct list_head *list = &dev->cqp_cmd_head;
81662306a36Sopenharmony_ci
81762306a36Sopenharmony_ci	if (list_empty(list))
81862306a36Sopenharmony_ci		return NULL;
81962306a36Sopenharmony_ci
82062306a36Sopenharmony_ci	entry = list->next;
82162306a36Sopenharmony_ci	list_del(entry);
82262306a36Sopenharmony_ci
82362306a36Sopenharmony_ci	return entry;
82462306a36Sopenharmony_ci}
82562306a36Sopenharmony_ci
82662306a36Sopenharmony_ci/**
82762306a36Sopenharmony_ci * irdma_cqp_sds_cmd - create cqp command for sd
82862306a36Sopenharmony_ci * @dev: hardware control device structure
82962306a36Sopenharmony_ci * @sdinfo: information for sd cqp
83062306a36Sopenharmony_ci *
83162306a36Sopenharmony_ci */
83262306a36Sopenharmony_ciint irdma_cqp_sds_cmd(struct irdma_sc_dev *dev,
83362306a36Sopenharmony_ci		      struct irdma_update_sds_info *sdinfo)
83462306a36Sopenharmony_ci{
83562306a36Sopenharmony_ci	struct irdma_cqp_request *cqp_request;
83662306a36Sopenharmony_ci	struct cqp_cmds_info *cqp_info;
83762306a36Sopenharmony_ci	struct irdma_pci_f *rf = dev_to_rf(dev);
83862306a36Sopenharmony_ci	int status;
83962306a36Sopenharmony_ci
84062306a36Sopenharmony_ci	cqp_request = irdma_alloc_and_get_cqp_request(&rf->cqp, true);
84162306a36Sopenharmony_ci	if (!cqp_request)
84262306a36Sopenharmony_ci		return -ENOMEM;
84362306a36Sopenharmony_ci
84462306a36Sopenharmony_ci	cqp_info = &cqp_request->info;
84562306a36Sopenharmony_ci	memcpy(&cqp_info->in.u.update_pe_sds.info, sdinfo,
84662306a36Sopenharmony_ci	       sizeof(cqp_info->in.u.update_pe_sds.info));
84762306a36Sopenharmony_ci	cqp_info->cqp_cmd = IRDMA_OP_UPDATE_PE_SDS;
84862306a36Sopenharmony_ci	cqp_info->post_sq = 1;
84962306a36Sopenharmony_ci	cqp_info->in.u.update_pe_sds.dev = dev;
85062306a36Sopenharmony_ci	cqp_info->in.u.update_pe_sds.scratch = (uintptr_t)cqp_request;
85162306a36Sopenharmony_ci
85262306a36Sopenharmony_ci	status = irdma_handle_cqp_op(rf, cqp_request);
85362306a36Sopenharmony_ci	irdma_put_cqp_request(&rf->cqp, cqp_request);
85462306a36Sopenharmony_ci
85562306a36Sopenharmony_ci	return status;
85662306a36Sopenharmony_ci}
85762306a36Sopenharmony_ci
85862306a36Sopenharmony_ci/**
85962306a36Sopenharmony_ci * irdma_cqp_qp_suspend_resume - cqp command for suspend/resume
86062306a36Sopenharmony_ci * @qp: hardware control qp
86162306a36Sopenharmony_ci * @op: suspend or resume
86262306a36Sopenharmony_ci */
86362306a36Sopenharmony_ciint irdma_cqp_qp_suspend_resume(struct irdma_sc_qp *qp, u8 op)
86462306a36Sopenharmony_ci{
86562306a36Sopenharmony_ci	struct irdma_sc_dev *dev = qp->dev;
86662306a36Sopenharmony_ci	struct irdma_cqp_request *cqp_request;
86762306a36Sopenharmony_ci	struct irdma_sc_cqp *cqp = dev->cqp;
86862306a36Sopenharmony_ci	struct cqp_cmds_info *cqp_info;
86962306a36Sopenharmony_ci	struct irdma_pci_f *rf = dev_to_rf(dev);
87062306a36Sopenharmony_ci	int status;
87162306a36Sopenharmony_ci
87262306a36Sopenharmony_ci	cqp_request = irdma_alloc_and_get_cqp_request(&rf->cqp, false);
87362306a36Sopenharmony_ci	if (!cqp_request)
87462306a36Sopenharmony_ci		return -ENOMEM;
87562306a36Sopenharmony_ci
87662306a36Sopenharmony_ci	cqp_info = &cqp_request->info;
87762306a36Sopenharmony_ci	cqp_info->cqp_cmd = op;
87862306a36Sopenharmony_ci	cqp_info->in.u.suspend_resume.cqp = cqp;
87962306a36Sopenharmony_ci	cqp_info->in.u.suspend_resume.qp = qp;
88062306a36Sopenharmony_ci	cqp_info->in.u.suspend_resume.scratch = (uintptr_t)cqp_request;
88162306a36Sopenharmony_ci
88262306a36Sopenharmony_ci	status = irdma_handle_cqp_op(rf, cqp_request);
88362306a36Sopenharmony_ci	irdma_put_cqp_request(&rf->cqp, cqp_request);
88462306a36Sopenharmony_ci
88562306a36Sopenharmony_ci	return status;
88662306a36Sopenharmony_ci}
88762306a36Sopenharmony_ci
88862306a36Sopenharmony_ci/**
88962306a36Sopenharmony_ci * irdma_term_modify_qp - modify qp for term message
89062306a36Sopenharmony_ci * @qp: hardware control qp
89162306a36Sopenharmony_ci * @next_state: qp's next state
89262306a36Sopenharmony_ci * @term: terminate code
89362306a36Sopenharmony_ci * @term_len: length
89462306a36Sopenharmony_ci */
89562306a36Sopenharmony_civoid irdma_term_modify_qp(struct irdma_sc_qp *qp, u8 next_state, u8 term,
89662306a36Sopenharmony_ci			  u8 term_len)
89762306a36Sopenharmony_ci{
89862306a36Sopenharmony_ci	struct irdma_qp *iwqp;
89962306a36Sopenharmony_ci
90062306a36Sopenharmony_ci	iwqp = qp->qp_uk.back_qp;
90162306a36Sopenharmony_ci	irdma_next_iw_state(iwqp, next_state, 0, term, term_len);
90262306a36Sopenharmony_ci};
90362306a36Sopenharmony_ci
90462306a36Sopenharmony_ci/**
90562306a36Sopenharmony_ci * irdma_terminate_done - after terminate is completed
90662306a36Sopenharmony_ci * @qp: hardware control qp
90762306a36Sopenharmony_ci * @timeout_occurred: indicates if terminate timer expired
90862306a36Sopenharmony_ci */
90962306a36Sopenharmony_civoid irdma_terminate_done(struct irdma_sc_qp *qp, int timeout_occurred)
91062306a36Sopenharmony_ci{
91162306a36Sopenharmony_ci	struct irdma_qp *iwqp;
91262306a36Sopenharmony_ci	u8 hte = 0;
91362306a36Sopenharmony_ci	bool first_time;
91462306a36Sopenharmony_ci	unsigned long flags;
91562306a36Sopenharmony_ci
91662306a36Sopenharmony_ci	iwqp = qp->qp_uk.back_qp;
91762306a36Sopenharmony_ci	spin_lock_irqsave(&iwqp->lock, flags);
91862306a36Sopenharmony_ci	if (iwqp->hte_added) {
91962306a36Sopenharmony_ci		iwqp->hte_added = 0;
92062306a36Sopenharmony_ci		hte = 1;
92162306a36Sopenharmony_ci	}
92262306a36Sopenharmony_ci	first_time = !(qp->term_flags & IRDMA_TERM_DONE);
92362306a36Sopenharmony_ci	qp->term_flags |= IRDMA_TERM_DONE;
92462306a36Sopenharmony_ci	spin_unlock_irqrestore(&iwqp->lock, flags);
92562306a36Sopenharmony_ci	if (first_time) {
92662306a36Sopenharmony_ci		if (!timeout_occurred)
92762306a36Sopenharmony_ci			irdma_terminate_del_timer(qp);
92862306a36Sopenharmony_ci
92962306a36Sopenharmony_ci		irdma_next_iw_state(iwqp, IRDMA_QP_STATE_ERROR, hte, 0, 0);
93062306a36Sopenharmony_ci		irdma_cm_disconn(iwqp);
93162306a36Sopenharmony_ci	}
93262306a36Sopenharmony_ci}
93362306a36Sopenharmony_ci
93462306a36Sopenharmony_cistatic void irdma_terminate_timeout(struct timer_list *t)
93562306a36Sopenharmony_ci{
93662306a36Sopenharmony_ci	struct irdma_qp *iwqp = from_timer(iwqp, t, terminate_timer);
93762306a36Sopenharmony_ci	struct irdma_sc_qp *qp = &iwqp->sc_qp;
93862306a36Sopenharmony_ci
93962306a36Sopenharmony_ci	irdma_terminate_done(qp, 1);
94062306a36Sopenharmony_ci	irdma_qp_rem_ref(&iwqp->ibqp);
94162306a36Sopenharmony_ci}
94262306a36Sopenharmony_ci
94362306a36Sopenharmony_ci/**
94462306a36Sopenharmony_ci * irdma_terminate_start_timer - start terminate timeout
94562306a36Sopenharmony_ci * @qp: hardware control qp
94662306a36Sopenharmony_ci */
94762306a36Sopenharmony_civoid irdma_terminate_start_timer(struct irdma_sc_qp *qp)
94862306a36Sopenharmony_ci{
94962306a36Sopenharmony_ci	struct irdma_qp *iwqp;
95062306a36Sopenharmony_ci
95162306a36Sopenharmony_ci	iwqp = qp->qp_uk.back_qp;
95262306a36Sopenharmony_ci	irdma_qp_add_ref(&iwqp->ibqp);
95362306a36Sopenharmony_ci	timer_setup(&iwqp->terminate_timer, irdma_terminate_timeout, 0);
95462306a36Sopenharmony_ci	iwqp->terminate_timer.expires = jiffies + HZ;
95562306a36Sopenharmony_ci
95662306a36Sopenharmony_ci	add_timer(&iwqp->terminate_timer);
95762306a36Sopenharmony_ci}
95862306a36Sopenharmony_ci
95962306a36Sopenharmony_ci/**
96062306a36Sopenharmony_ci * irdma_terminate_del_timer - delete terminate timeout
96162306a36Sopenharmony_ci * @qp: hardware control qp
96262306a36Sopenharmony_ci */
96362306a36Sopenharmony_civoid irdma_terminate_del_timer(struct irdma_sc_qp *qp)
96462306a36Sopenharmony_ci{
96562306a36Sopenharmony_ci	struct irdma_qp *iwqp;
96662306a36Sopenharmony_ci	int ret;
96762306a36Sopenharmony_ci
96862306a36Sopenharmony_ci	iwqp = qp->qp_uk.back_qp;
96962306a36Sopenharmony_ci	ret = del_timer(&iwqp->terminate_timer);
97062306a36Sopenharmony_ci	if (ret)
97162306a36Sopenharmony_ci		irdma_qp_rem_ref(&iwqp->ibqp);
97262306a36Sopenharmony_ci}
97362306a36Sopenharmony_ci
97462306a36Sopenharmony_ci/**
97562306a36Sopenharmony_ci * irdma_cqp_query_fpm_val_cmd - send cqp command for fpm
97662306a36Sopenharmony_ci * @dev: function device struct
97762306a36Sopenharmony_ci * @val_mem: buffer for fpm
97862306a36Sopenharmony_ci * @hmc_fn_id: function id for fpm
97962306a36Sopenharmony_ci */
98062306a36Sopenharmony_ciint irdma_cqp_query_fpm_val_cmd(struct irdma_sc_dev *dev,
98162306a36Sopenharmony_ci				struct irdma_dma_mem *val_mem, u8 hmc_fn_id)
98262306a36Sopenharmony_ci{
98362306a36Sopenharmony_ci	struct irdma_cqp_request *cqp_request;
98462306a36Sopenharmony_ci	struct cqp_cmds_info *cqp_info;
98562306a36Sopenharmony_ci	struct irdma_pci_f *rf = dev_to_rf(dev);
98662306a36Sopenharmony_ci	int status;
98762306a36Sopenharmony_ci
98862306a36Sopenharmony_ci	cqp_request = irdma_alloc_and_get_cqp_request(&rf->cqp, true);
98962306a36Sopenharmony_ci	if (!cqp_request)
99062306a36Sopenharmony_ci		return -ENOMEM;
99162306a36Sopenharmony_ci
99262306a36Sopenharmony_ci	cqp_info = &cqp_request->info;
99362306a36Sopenharmony_ci	cqp_request->param = NULL;
99462306a36Sopenharmony_ci	cqp_info->in.u.query_fpm_val.cqp = dev->cqp;
99562306a36Sopenharmony_ci	cqp_info->in.u.query_fpm_val.fpm_val_pa = val_mem->pa;
99662306a36Sopenharmony_ci	cqp_info->in.u.query_fpm_val.fpm_val_va = val_mem->va;
99762306a36Sopenharmony_ci	cqp_info->in.u.query_fpm_val.hmc_fn_id = hmc_fn_id;
99862306a36Sopenharmony_ci	cqp_info->cqp_cmd = IRDMA_OP_QUERY_FPM_VAL;
99962306a36Sopenharmony_ci	cqp_info->post_sq = 1;
100062306a36Sopenharmony_ci	cqp_info->in.u.query_fpm_val.scratch = (uintptr_t)cqp_request;
100162306a36Sopenharmony_ci
100262306a36Sopenharmony_ci	status = irdma_handle_cqp_op(rf, cqp_request);
100362306a36Sopenharmony_ci	irdma_put_cqp_request(&rf->cqp, cqp_request);
100462306a36Sopenharmony_ci
100562306a36Sopenharmony_ci	return status;
100662306a36Sopenharmony_ci}
100762306a36Sopenharmony_ci
100862306a36Sopenharmony_ci/**
100962306a36Sopenharmony_ci * irdma_cqp_commit_fpm_val_cmd - commit fpm values in hw
101062306a36Sopenharmony_ci * @dev: hardware control device structure
101162306a36Sopenharmony_ci * @val_mem: buffer with fpm values
101262306a36Sopenharmony_ci * @hmc_fn_id: function id for fpm
101362306a36Sopenharmony_ci */
101462306a36Sopenharmony_ciint irdma_cqp_commit_fpm_val_cmd(struct irdma_sc_dev *dev,
101562306a36Sopenharmony_ci				 struct irdma_dma_mem *val_mem, u8 hmc_fn_id)
101662306a36Sopenharmony_ci{
101762306a36Sopenharmony_ci	struct irdma_cqp_request *cqp_request;
101862306a36Sopenharmony_ci	struct cqp_cmds_info *cqp_info;
101962306a36Sopenharmony_ci	struct irdma_pci_f *rf = dev_to_rf(dev);
102062306a36Sopenharmony_ci	int status;
102162306a36Sopenharmony_ci
102262306a36Sopenharmony_ci	cqp_request = irdma_alloc_and_get_cqp_request(&rf->cqp, true);
102362306a36Sopenharmony_ci	if (!cqp_request)
102462306a36Sopenharmony_ci		return -ENOMEM;
102562306a36Sopenharmony_ci
102662306a36Sopenharmony_ci	cqp_info = &cqp_request->info;
102762306a36Sopenharmony_ci	cqp_request->param = NULL;
102862306a36Sopenharmony_ci	cqp_info->in.u.commit_fpm_val.cqp = dev->cqp;
102962306a36Sopenharmony_ci	cqp_info->in.u.commit_fpm_val.fpm_val_pa = val_mem->pa;
103062306a36Sopenharmony_ci	cqp_info->in.u.commit_fpm_val.fpm_val_va = val_mem->va;
103162306a36Sopenharmony_ci	cqp_info->in.u.commit_fpm_val.hmc_fn_id = hmc_fn_id;
103262306a36Sopenharmony_ci	cqp_info->cqp_cmd = IRDMA_OP_COMMIT_FPM_VAL;
103362306a36Sopenharmony_ci	cqp_info->post_sq = 1;
103462306a36Sopenharmony_ci	cqp_info->in.u.commit_fpm_val.scratch = (uintptr_t)cqp_request;
103562306a36Sopenharmony_ci
103662306a36Sopenharmony_ci	status = irdma_handle_cqp_op(rf, cqp_request);
103762306a36Sopenharmony_ci	irdma_put_cqp_request(&rf->cqp, cqp_request);
103862306a36Sopenharmony_ci
103962306a36Sopenharmony_ci	return status;
104062306a36Sopenharmony_ci}
104162306a36Sopenharmony_ci
104262306a36Sopenharmony_ci/**
104362306a36Sopenharmony_ci * irdma_cqp_cq_create_cmd - create a cq for the cqp
104462306a36Sopenharmony_ci * @dev: device pointer
104562306a36Sopenharmony_ci * @cq: pointer to created cq
104662306a36Sopenharmony_ci */
104762306a36Sopenharmony_ciint irdma_cqp_cq_create_cmd(struct irdma_sc_dev *dev, struct irdma_sc_cq *cq)
104862306a36Sopenharmony_ci{
104962306a36Sopenharmony_ci	struct irdma_pci_f *rf = dev_to_rf(dev);
105062306a36Sopenharmony_ci	struct irdma_cqp *iwcqp = &rf->cqp;
105162306a36Sopenharmony_ci	struct irdma_cqp_request *cqp_request;
105262306a36Sopenharmony_ci	struct cqp_cmds_info *cqp_info;
105362306a36Sopenharmony_ci	int status;
105462306a36Sopenharmony_ci
105562306a36Sopenharmony_ci	cqp_request = irdma_alloc_and_get_cqp_request(iwcqp, true);
105662306a36Sopenharmony_ci	if (!cqp_request)
105762306a36Sopenharmony_ci		return -ENOMEM;
105862306a36Sopenharmony_ci
105962306a36Sopenharmony_ci	cqp_info = &cqp_request->info;
106062306a36Sopenharmony_ci	cqp_info->cqp_cmd = IRDMA_OP_CQ_CREATE;
106162306a36Sopenharmony_ci	cqp_info->post_sq = 1;
106262306a36Sopenharmony_ci	cqp_info->in.u.cq_create.cq = cq;
106362306a36Sopenharmony_ci	cqp_info->in.u.cq_create.scratch = (uintptr_t)cqp_request;
106462306a36Sopenharmony_ci
106562306a36Sopenharmony_ci	status = irdma_handle_cqp_op(rf, cqp_request);
106662306a36Sopenharmony_ci	irdma_put_cqp_request(iwcqp, cqp_request);
106762306a36Sopenharmony_ci
106862306a36Sopenharmony_ci	return status;
106962306a36Sopenharmony_ci}
107062306a36Sopenharmony_ci
107162306a36Sopenharmony_ci/**
107262306a36Sopenharmony_ci * irdma_cqp_qp_create_cmd - create a qp for the cqp
107362306a36Sopenharmony_ci * @dev: device pointer
107462306a36Sopenharmony_ci * @qp: pointer to created qp
107562306a36Sopenharmony_ci */
107662306a36Sopenharmony_ciint irdma_cqp_qp_create_cmd(struct irdma_sc_dev *dev, struct irdma_sc_qp *qp)
107762306a36Sopenharmony_ci{
107862306a36Sopenharmony_ci	struct irdma_pci_f *rf = dev_to_rf(dev);
107962306a36Sopenharmony_ci	struct irdma_cqp *iwcqp = &rf->cqp;
108062306a36Sopenharmony_ci	struct irdma_cqp_request *cqp_request;
108162306a36Sopenharmony_ci	struct cqp_cmds_info *cqp_info;
108262306a36Sopenharmony_ci	struct irdma_create_qp_info *qp_info;
108362306a36Sopenharmony_ci	int status;
108462306a36Sopenharmony_ci
108562306a36Sopenharmony_ci	cqp_request = irdma_alloc_and_get_cqp_request(iwcqp, true);
108662306a36Sopenharmony_ci	if (!cqp_request)
108762306a36Sopenharmony_ci		return -ENOMEM;
108862306a36Sopenharmony_ci
108962306a36Sopenharmony_ci	cqp_info = &cqp_request->info;
109062306a36Sopenharmony_ci	qp_info = &cqp_request->info.in.u.qp_create.info;
109162306a36Sopenharmony_ci	memset(qp_info, 0, sizeof(*qp_info));
109262306a36Sopenharmony_ci	qp_info->cq_num_valid = true;
109362306a36Sopenharmony_ci	qp_info->next_iwarp_state = IRDMA_QP_STATE_RTS;
109462306a36Sopenharmony_ci	cqp_info->cqp_cmd = IRDMA_OP_QP_CREATE;
109562306a36Sopenharmony_ci	cqp_info->post_sq = 1;
109662306a36Sopenharmony_ci	cqp_info->in.u.qp_create.qp = qp;
109762306a36Sopenharmony_ci	cqp_info->in.u.qp_create.scratch = (uintptr_t)cqp_request;
109862306a36Sopenharmony_ci
109962306a36Sopenharmony_ci	status = irdma_handle_cqp_op(rf, cqp_request);
110062306a36Sopenharmony_ci	irdma_put_cqp_request(iwcqp, cqp_request);
110162306a36Sopenharmony_ci
110262306a36Sopenharmony_ci	return status;
110362306a36Sopenharmony_ci}
110462306a36Sopenharmony_ci
110562306a36Sopenharmony_ci/**
110662306a36Sopenharmony_ci * irdma_dealloc_push_page - free a push page for qp
110762306a36Sopenharmony_ci * @rf: RDMA PCI function
110862306a36Sopenharmony_ci * @qp: hardware control qp
110962306a36Sopenharmony_ci */
111062306a36Sopenharmony_cistatic void irdma_dealloc_push_page(struct irdma_pci_f *rf,
111162306a36Sopenharmony_ci				    struct irdma_sc_qp *qp)
111262306a36Sopenharmony_ci{
111362306a36Sopenharmony_ci	struct irdma_cqp_request *cqp_request;
111462306a36Sopenharmony_ci	struct cqp_cmds_info *cqp_info;
111562306a36Sopenharmony_ci	int status;
111662306a36Sopenharmony_ci
111762306a36Sopenharmony_ci	if (qp->push_idx == IRDMA_INVALID_PUSH_PAGE_INDEX)
111862306a36Sopenharmony_ci		return;
111962306a36Sopenharmony_ci
112062306a36Sopenharmony_ci	cqp_request = irdma_alloc_and_get_cqp_request(&rf->cqp, false);
112162306a36Sopenharmony_ci	if (!cqp_request)
112262306a36Sopenharmony_ci		return;
112362306a36Sopenharmony_ci
112462306a36Sopenharmony_ci	cqp_info = &cqp_request->info;
112562306a36Sopenharmony_ci	cqp_info->cqp_cmd = IRDMA_OP_MANAGE_PUSH_PAGE;
112662306a36Sopenharmony_ci	cqp_info->post_sq = 1;
112762306a36Sopenharmony_ci	cqp_info->in.u.manage_push_page.info.push_idx = qp->push_idx;
112862306a36Sopenharmony_ci	cqp_info->in.u.manage_push_page.info.qs_handle = qp->qs_handle;
112962306a36Sopenharmony_ci	cqp_info->in.u.manage_push_page.info.free_page = 1;
113062306a36Sopenharmony_ci	cqp_info->in.u.manage_push_page.info.push_page_type = 0;
113162306a36Sopenharmony_ci	cqp_info->in.u.manage_push_page.cqp = &rf->cqp.sc_cqp;
113262306a36Sopenharmony_ci	cqp_info->in.u.manage_push_page.scratch = (uintptr_t)cqp_request;
113362306a36Sopenharmony_ci	status = irdma_handle_cqp_op(rf, cqp_request);
113462306a36Sopenharmony_ci	if (!status)
113562306a36Sopenharmony_ci		qp->push_idx = IRDMA_INVALID_PUSH_PAGE_INDEX;
113662306a36Sopenharmony_ci	irdma_put_cqp_request(&rf->cqp, cqp_request);
113762306a36Sopenharmony_ci}
113862306a36Sopenharmony_ci
113962306a36Sopenharmony_ci/**
114062306a36Sopenharmony_ci * irdma_free_qp_rsrc - free up memory resources for qp
114162306a36Sopenharmony_ci * @iwqp: qp ptr (user or kernel)
114262306a36Sopenharmony_ci */
114362306a36Sopenharmony_civoid irdma_free_qp_rsrc(struct irdma_qp *iwqp)
114462306a36Sopenharmony_ci{
114562306a36Sopenharmony_ci	struct irdma_device *iwdev = iwqp->iwdev;
114662306a36Sopenharmony_ci	struct irdma_pci_f *rf = iwdev->rf;
114762306a36Sopenharmony_ci	u32 qp_num = iwqp->ibqp.qp_num;
114862306a36Sopenharmony_ci
114962306a36Sopenharmony_ci	irdma_ieq_cleanup_qp(iwdev->vsi.ieq, &iwqp->sc_qp);
115062306a36Sopenharmony_ci	irdma_dealloc_push_page(rf, &iwqp->sc_qp);
115162306a36Sopenharmony_ci	if (iwqp->sc_qp.vsi) {
115262306a36Sopenharmony_ci		irdma_qp_rem_qos(&iwqp->sc_qp);
115362306a36Sopenharmony_ci		iwqp->sc_qp.dev->ws_remove(iwqp->sc_qp.vsi,
115462306a36Sopenharmony_ci					   iwqp->sc_qp.user_pri);
115562306a36Sopenharmony_ci	}
115662306a36Sopenharmony_ci
115762306a36Sopenharmony_ci	if (qp_num > 2)
115862306a36Sopenharmony_ci		irdma_free_rsrc(rf, rf->allocated_qps, qp_num);
115962306a36Sopenharmony_ci	dma_free_coherent(rf->sc_dev.hw->device, iwqp->q2_ctx_mem.size,
116062306a36Sopenharmony_ci			  iwqp->q2_ctx_mem.va, iwqp->q2_ctx_mem.pa);
116162306a36Sopenharmony_ci	iwqp->q2_ctx_mem.va = NULL;
116262306a36Sopenharmony_ci	dma_free_coherent(rf->sc_dev.hw->device, iwqp->kqp.dma_mem.size,
116362306a36Sopenharmony_ci			  iwqp->kqp.dma_mem.va, iwqp->kqp.dma_mem.pa);
116462306a36Sopenharmony_ci	iwqp->kqp.dma_mem.va = NULL;
116562306a36Sopenharmony_ci	kfree(iwqp->kqp.sq_wrid_mem);
116662306a36Sopenharmony_ci	kfree(iwqp->kqp.rq_wrid_mem);
116762306a36Sopenharmony_ci}
116862306a36Sopenharmony_ci
116962306a36Sopenharmony_ci/**
117062306a36Sopenharmony_ci * irdma_cq_wq_destroy - send cq destroy cqp
117162306a36Sopenharmony_ci * @rf: RDMA PCI function
117262306a36Sopenharmony_ci * @cq: hardware control cq
117362306a36Sopenharmony_ci */
117462306a36Sopenharmony_civoid irdma_cq_wq_destroy(struct irdma_pci_f *rf, struct irdma_sc_cq *cq)
117562306a36Sopenharmony_ci{
117662306a36Sopenharmony_ci	struct irdma_cqp_request *cqp_request;
117762306a36Sopenharmony_ci	struct cqp_cmds_info *cqp_info;
117862306a36Sopenharmony_ci
117962306a36Sopenharmony_ci	cqp_request = irdma_alloc_and_get_cqp_request(&rf->cqp, true);
118062306a36Sopenharmony_ci	if (!cqp_request)
118162306a36Sopenharmony_ci		return;
118262306a36Sopenharmony_ci
118362306a36Sopenharmony_ci	cqp_info = &cqp_request->info;
118462306a36Sopenharmony_ci	cqp_info->cqp_cmd = IRDMA_OP_CQ_DESTROY;
118562306a36Sopenharmony_ci	cqp_info->post_sq = 1;
118662306a36Sopenharmony_ci	cqp_info->in.u.cq_destroy.cq = cq;
118762306a36Sopenharmony_ci	cqp_info->in.u.cq_destroy.scratch = (uintptr_t)cqp_request;
118862306a36Sopenharmony_ci
118962306a36Sopenharmony_ci	irdma_handle_cqp_op(rf, cqp_request);
119062306a36Sopenharmony_ci	irdma_put_cqp_request(&rf->cqp, cqp_request);
119162306a36Sopenharmony_ci}
119262306a36Sopenharmony_ci
119362306a36Sopenharmony_ci/**
119462306a36Sopenharmony_ci * irdma_hw_modify_qp_callback - handle state for modifyQPs that don't wait
119562306a36Sopenharmony_ci * @cqp_request: modify QP completion
119662306a36Sopenharmony_ci */
119762306a36Sopenharmony_cistatic void irdma_hw_modify_qp_callback(struct irdma_cqp_request *cqp_request)
119862306a36Sopenharmony_ci{
119962306a36Sopenharmony_ci	struct cqp_cmds_info *cqp_info;
120062306a36Sopenharmony_ci	struct irdma_qp *iwqp;
120162306a36Sopenharmony_ci
120262306a36Sopenharmony_ci	cqp_info = &cqp_request->info;
120362306a36Sopenharmony_ci	iwqp = cqp_info->in.u.qp_modify.qp->qp_uk.back_qp;
120462306a36Sopenharmony_ci	atomic_dec(&iwqp->hw_mod_qp_pend);
120562306a36Sopenharmony_ci	wake_up(&iwqp->mod_qp_waitq);
120662306a36Sopenharmony_ci}
120762306a36Sopenharmony_ci
120862306a36Sopenharmony_ci/**
120962306a36Sopenharmony_ci * irdma_hw_modify_qp - setup cqp for modify qp
121062306a36Sopenharmony_ci * @iwdev: RDMA device
121162306a36Sopenharmony_ci * @iwqp: qp ptr (user or kernel)
121262306a36Sopenharmony_ci * @info: info for modify qp
121362306a36Sopenharmony_ci * @wait: flag to wait or not for modify qp completion
121462306a36Sopenharmony_ci */
121562306a36Sopenharmony_ciint irdma_hw_modify_qp(struct irdma_device *iwdev, struct irdma_qp *iwqp,
121662306a36Sopenharmony_ci		       struct irdma_modify_qp_info *info, bool wait)
121762306a36Sopenharmony_ci{
121862306a36Sopenharmony_ci	int status;
121962306a36Sopenharmony_ci	struct irdma_pci_f *rf = iwdev->rf;
122062306a36Sopenharmony_ci	struct irdma_cqp_request *cqp_request;
122162306a36Sopenharmony_ci	struct cqp_cmds_info *cqp_info;
122262306a36Sopenharmony_ci	struct irdma_modify_qp_info *m_info;
122362306a36Sopenharmony_ci
122462306a36Sopenharmony_ci	cqp_request = irdma_alloc_and_get_cqp_request(&rf->cqp, wait);
122562306a36Sopenharmony_ci	if (!cqp_request)
122662306a36Sopenharmony_ci		return -ENOMEM;
122762306a36Sopenharmony_ci
122862306a36Sopenharmony_ci	if (!wait) {
122962306a36Sopenharmony_ci		cqp_request->callback_fcn = irdma_hw_modify_qp_callback;
123062306a36Sopenharmony_ci		atomic_inc(&iwqp->hw_mod_qp_pend);
123162306a36Sopenharmony_ci	}
123262306a36Sopenharmony_ci	cqp_info = &cqp_request->info;
123362306a36Sopenharmony_ci	m_info = &cqp_info->in.u.qp_modify.info;
123462306a36Sopenharmony_ci	memcpy(m_info, info, sizeof(*m_info));
123562306a36Sopenharmony_ci	cqp_info->cqp_cmd = IRDMA_OP_QP_MODIFY;
123662306a36Sopenharmony_ci	cqp_info->post_sq = 1;
123762306a36Sopenharmony_ci	cqp_info->in.u.qp_modify.qp = &iwqp->sc_qp;
123862306a36Sopenharmony_ci	cqp_info->in.u.qp_modify.scratch = (uintptr_t)cqp_request;
123962306a36Sopenharmony_ci	status = irdma_handle_cqp_op(rf, cqp_request);
124062306a36Sopenharmony_ci	irdma_put_cqp_request(&rf->cqp, cqp_request);
124162306a36Sopenharmony_ci	if (status) {
124262306a36Sopenharmony_ci		if (rdma_protocol_roce(&iwdev->ibdev, 1))
124362306a36Sopenharmony_ci			return status;
124462306a36Sopenharmony_ci
124562306a36Sopenharmony_ci		switch (m_info->next_iwarp_state) {
124662306a36Sopenharmony_ci			struct irdma_gen_ae_info ae_info;
124762306a36Sopenharmony_ci
124862306a36Sopenharmony_ci		case IRDMA_QP_STATE_RTS:
124962306a36Sopenharmony_ci		case IRDMA_QP_STATE_IDLE:
125062306a36Sopenharmony_ci		case IRDMA_QP_STATE_TERMINATE:
125162306a36Sopenharmony_ci		case IRDMA_QP_STATE_CLOSING:
125262306a36Sopenharmony_ci			if (info->curr_iwarp_state == IRDMA_QP_STATE_IDLE)
125362306a36Sopenharmony_ci				irdma_send_reset(iwqp->cm_node);
125462306a36Sopenharmony_ci			else
125562306a36Sopenharmony_ci				iwqp->sc_qp.term_flags = IRDMA_TERM_DONE;
125662306a36Sopenharmony_ci			if (!wait) {
125762306a36Sopenharmony_ci				ae_info.ae_code = IRDMA_AE_BAD_CLOSE;
125862306a36Sopenharmony_ci				ae_info.ae_src = 0;
125962306a36Sopenharmony_ci				irdma_gen_ae(rf, &iwqp->sc_qp, &ae_info, false);
126062306a36Sopenharmony_ci			} else {
126162306a36Sopenharmony_ci				cqp_request = irdma_alloc_and_get_cqp_request(&rf->cqp,
126262306a36Sopenharmony_ci									      wait);
126362306a36Sopenharmony_ci				if (!cqp_request)
126462306a36Sopenharmony_ci					return -ENOMEM;
126562306a36Sopenharmony_ci
126662306a36Sopenharmony_ci				cqp_info = &cqp_request->info;
126762306a36Sopenharmony_ci				m_info = &cqp_info->in.u.qp_modify.info;
126862306a36Sopenharmony_ci				memcpy(m_info, info, sizeof(*m_info));
126962306a36Sopenharmony_ci				cqp_info->cqp_cmd = IRDMA_OP_QP_MODIFY;
127062306a36Sopenharmony_ci				cqp_info->post_sq = 1;
127162306a36Sopenharmony_ci				cqp_info->in.u.qp_modify.qp = &iwqp->sc_qp;
127262306a36Sopenharmony_ci				cqp_info->in.u.qp_modify.scratch = (uintptr_t)cqp_request;
127362306a36Sopenharmony_ci				m_info->next_iwarp_state = IRDMA_QP_STATE_ERROR;
127462306a36Sopenharmony_ci				m_info->reset_tcp_conn = true;
127562306a36Sopenharmony_ci				irdma_handle_cqp_op(rf, cqp_request);
127662306a36Sopenharmony_ci				irdma_put_cqp_request(&rf->cqp, cqp_request);
127762306a36Sopenharmony_ci			}
127862306a36Sopenharmony_ci			break;
127962306a36Sopenharmony_ci		case IRDMA_QP_STATE_ERROR:
128062306a36Sopenharmony_ci		default:
128162306a36Sopenharmony_ci			break;
128262306a36Sopenharmony_ci		}
128362306a36Sopenharmony_ci	}
128462306a36Sopenharmony_ci
128562306a36Sopenharmony_ci	return status;
128662306a36Sopenharmony_ci}
128762306a36Sopenharmony_ci
128862306a36Sopenharmony_ci/**
128962306a36Sopenharmony_ci * irdma_cqp_cq_destroy_cmd - destroy the cqp cq
129062306a36Sopenharmony_ci * @dev: device pointer
129162306a36Sopenharmony_ci * @cq: pointer to cq
129262306a36Sopenharmony_ci */
129362306a36Sopenharmony_civoid irdma_cqp_cq_destroy_cmd(struct irdma_sc_dev *dev, struct irdma_sc_cq *cq)
129462306a36Sopenharmony_ci{
129562306a36Sopenharmony_ci	struct irdma_pci_f *rf = dev_to_rf(dev);
129662306a36Sopenharmony_ci
129762306a36Sopenharmony_ci	irdma_cq_wq_destroy(rf, cq);
129862306a36Sopenharmony_ci}
129962306a36Sopenharmony_ci
130062306a36Sopenharmony_ci/**
130162306a36Sopenharmony_ci * irdma_cqp_qp_destroy_cmd - destroy the cqp
130262306a36Sopenharmony_ci * @dev: device pointer
130362306a36Sopenharmony_ci * @qp: pointer to qp
130462306a36Sopenharmony_ci */
130562306a36Sopenharmony_ciint irdma_cqp_qp_destroy_cmd(struct irdma_sc_dev *dev, struct irdma_sc_qp *qp)
130662306a36Sopenharmony_ci{
130762306a36Sopenharmony_ci	struct irdma_pci_f *rf = dev_to_rf(dev);
130862306a36Sopenharmony_ci	struct irdma_cqp *iwcqp = &rf->cqp;
130962306a36Sopenharmony_ci	struct irdma_cqp_request *cqp_request;
131062306a36Sopenharmony_ci	struct cqp_cmds_info *cqp_info;
131162306a36Sopenharmony_ci	int status;
131262306a36Sopenharmony_ci
131362306a36Sopenharmony_ci	cqp_request = irdma_alloc_and_get_cqp_request(iwcqp, true);
131462306a36Sopenharmony_ci	if (!cqp_request)
131562306a36Sopenharmony_ci		return -ENOMEM;
131662306a36Sopenharmony_ci
131762306a36Sopenharmony_ci	cqp_info = &cqp_request->info;
131862306a36Sopenharmony_ci	memset(cqp_info, 0, sizeof(*cqp_info));
131962306a36Sopenharmony_ci	cqp_info->cqp_cmd = IRDMA_OP_QP_DESTROY;
132062306a36Sopenharmony_ci	cqp_info->post_sq = 1;
132162306a36Sopenharmony_ci	cqp_info->in.u.qp_destroy.qp = qp;
132262306a36Sopenharmony_ci	cqp_info->in.u.qp_destroy.scratch = (uintptr_t)cqp_request;
132362306a36Sopenharmony_ci	cqp_info->in.u.qp_destroy.remove_hash_idx = true;
132462306a36Sopenharmony_ci
132562306a36Sopenharmony_ci	status = irdma_handle_cqp_op(rf, cqp_request);
132662306a36Sopenharmony_ci	irdma_put_cqp_request(&rf->cqp, cqp_request);
132762306a36Sopenharmony_ci
132862306a36Sopenharmony_ci	return status;
132962306a36Sopenharmony_ci}
133062306a36Sopenharmony_ci
133162306a36Sopenharmony_ci/**
133262306a36Sopenharmony_ci * irdma_ieq_mpa_crc_ae - generate AE for crc error
133362306a36Sopenharmony_ci * @dev: hardware control device structure
133462306a36Sopenharmony_ci * @qp: hardware control qp
133562306a36Sopenharmony_ci */
133662306a36Sopenharmony_civoid irdma_ieq_mpa_crc_ae(struct irdma_sc_dev *dev, struct irdma_sc_qp *qp)
133762306a36Sopenharmony_ci{
133862306a36Sopenharmony_ci	struct irdma_gen_ae_info info = {};
133962306a36Sopenharmony_ci	struct irdma_pci_f *rf = dev_to_rf(dev);
134062306a36Sopenharmony_ci
134162306a36Sopenharmony_ci	ibdev_dbg(&rf->iwdev->ibdev, "AEQ: Generate MPA CRC AE\n");
134262306a36Sopenharmony_ci	info.ae_code = IRDMA_AE_LLP_RECEIVED_MPA_CRC_ERROR;
134362306a36Sopenharmony_ci	info.ae_src = IRDMA_AE_SOURCE_RQ;
134462306a36Sopenharmony_ci	irdma_gen_ae(rf, qp, &info, false);
134562306a36Sopenharmony_ci}
134662306a36Sopenharmony_ci
134762306a36Sopenharmony_ci/**
134862306a36Sopenharmony_ci * irdma_init_hash_desc - initialize hash for crc calculation
134962306a36Sopenharmony_ci * @desc: cryption type
135062306a36Sopenharmony_ci */
135162306a36Sopenharmony_ciint irdma_init_hash_desc(struct shash_desc **desc)
135262306a36Sopenharmony_ci{
135362306a36Sopenharmony_ci	struct crypto_shash *tfm;
135462306a36Sopenharmony_ci	struct shash_desc *tdesc;
135562306a36Sopenharmony_ci
135662306a36Sopenharmony_ci	tfm = crypto_alloc_shash("crc32c", 0, 0);
135762306a36Sopenharmony_ci	if (IS_ERR(tfm))
135862306a36Sopenharmony_ci		return -EINVAL;
135962306a36Sopenharmony_ci
136062306a36Sopenharmony_ci	tdesc = kzalloc(sizeof(*tdesc) + crypto_shash_descsize(tfm),
136162306a36Sopenharmony_ci			GFP_KERNEL);
136262306a36Sopenharmony_ci	if (!tdesc) {
136362306a36Sopenharmony_ci		crypto_free_shash(tfm);
136462306a36Sopenharmony_ci		return -EINVAL;
136562306a36Sopenharmony_ci	}
136662306a36Sopenharmony_ci
136762306a36Sopenharmony_ci	tdesc->tfm = tfm;
136862306a36Sopenharmony_ci	*desc = tdesc;
136962306a36Sopenharmony_ci
137062306a36Sopenharmony_ci	return 0;
137162306a36Sopenharmony_ci}
137262306a36Sopenharmony_ci
137362306a36Sopenharmony_ci/**
137462306a36Sopenharmony_ci * irdma_free_hash_desc - free hash desc
137562306a36Sopenharmony_ci * @desc: to be freed
137662306a36Sopenharmony_ci */
137762306a36Sopenharmony_civoid irdma_free_hash_desc(struct shash_desc *desc)
137862306a36Sopenharmony_ci{
137962306a36Sopenharmony_ci	if (desc) {
138062306a36Sopenharmony_ci		crypto_free_shash(desc->tfm);
138162306a36Sopenharmony_ci		kfree(desc);
138262306a36Sopenharmony_ci	}
138362306a36Sopenharmony_ci}
138462306a36Sopenharmony_ci
138562306a36Sopenharmony_ci/**
138662306a36Sopenharmony_ci * irdma_ieq_check_mpacrc - check if mpa crc is OK
138762306a36Sopenharmony_ci * @desc: desc for hash
138862306a36Sopenharmony_ci * @addr: address of buffer for crc
138962306a36Sopenharmony_ci * @len: length of buffer
139062306a36Sopenharmony_ci * @val: value to be compared
139162306a36Sopenharmony_ci */
139262306a36Sopenharmony_ciint irdma_ieq_check_mpacrc(struct shash_desc *desc, void *addr, u32 len,
139362306a36Sopenharmony_ci			   u32 val)
139462306a36Sopenharmony_ci{
139562306a36Sopenharmony_ci	u32 crc = 0;
139662306a36Sopenharmony_ci	int ret;
139762306a36Sopenharmony_ci	int ret_code = 0;
139862306a36Sopenharmony_ci
139962306a36Sopenharmony_ci	crypto_shash_init(desc);
140062306a36Sopenharmony_ci	ret = crypto_shash_update(desc, addr, len);
140162306a36Sopenharmony_ci	if (!ret)
140262306a36Sopenharmony_ci		crypto_shash_final(desc, (u8 *)&crc);
140362306a36Sopenharmony_ci	if (crc != val)
140462306a36Sopenharmony_ci		ret_code = -EINVAL;
140562306a36Sopenharmony_ci
140662306a36Sopenharmony_ci	return ret_code;
140762306a36Sopenharmony_ci}
140862306a36Sopenharmony_ci
140962306a36Sopenharmony_ci/**
141062306a36Sopenharmony_ci * irdma_ieq_get_qp - get qp based on quad in puda buffer
141162306a36Sopenharmony_ci * @dev: hardware control device structure
141262306a36Sopenharmony_ci * @buf: receive puda buffer on exception q
141362306a36Sopenharmony_ci */
141462306a36Sopenharmony_cistruct irdma_sc_qp *irdma_ieq_get_qp(struct irdma_sc_dev *dev,
141562306a36Sopenharmony_ci				     struct irdma_puda_buf *buf)
141662306a36Sopenharmony_ci{
141762306a36Sopenharmony_ci	struct irdma_qp *iwqp;
141862306a36Sopenharmony_ci	struct irdma_cm_node *cm_node;
141962306a36Sopenharmony_ci	struct irdma_device *iwdev = buf->vsi->back_vsi;
142062306a36Sopenharmony_ci	u32 loc_addr[4] = {};
142162306a36Sopenharmony_ci	u32 rem_addr[4] = {};
142262306a36Sopenharmony_ci	u16 loc_port, rem_port;
142362306a36Sopenharmony_ci	struct ipv6hdr *ip6h;
142462306a36Sopenharmony_ci	struct iphdr *iph = (struct iphdr *)buf->iph;
142562306a36Sopenharmony_ci	struct tcphdr *tcph = (struct tcphdr *)buf->tcph;
142662306a36Sopenharmony_ci
142762306a36Sopenharmony_ci	if (iph->version == 4) {
142862306a36Sopenharmony_ci		loc_addr[0] = ntohl(iph->daddr);
142962306a36Sopenharmony_ci		rem_addr[0] = ntohl(iph->saddr);
143062306a36Sopenharmony_ci	} else {
143162306a36Sopenharmony_ci		ip6h = (struct ipv6hdr *)buf->iph;
143262306a36Sopenharmony_ci		irdma_copy_ip_ntohl(loc_addr, ip6h->daddr.in6_u.u6_addr32);
143362306a36Sopenharmony_ci		irdma_copy_ip_ntohl(rem_addr, ip6h->saddr.in6_u.u6_addr32);
143462306a36Sopenharmony_ci	}
143562306a36Sopenharmony_ci	loc_port = ntohs(tcph->dest);
143662306a36Sopenharmony_ci	rem_port = ntohs(tcph->source);
143762306a36Sopenharmony_ci	cm_node = irdma_find_node(&iwdev->cm_core, rem_port, rem_addr, loc_port,
143862306a36Sopenharmony_ci				  loc_addr, buf->vlan_valid ? buf->vlan_id : 0xFFFF);
143962306a36Sopenharmony_ci	if (!cm_node)
144062306a36Sopenharmony_ci		return NULL;
144162306a36Sopenharmony_ci
144262306a36Sopenharmony_ci	iwqp = cm_node->iwqp;
144362306a36Sopenharmony_ci	irdma_rem_ref_cm_node(cm_node);
144462306a36Sopenharmony_ci
144562306a36Sopenharmony_ci	return &iwqp->sc_qp;
144662306a36Sopenharmony_ci}
144762306a36Sopenharmony_ci
144862306a36Sopenharmony_ci/**
144962306a36Sopenharmony_ci * irdma_send_ieq_ack - ACKs for duplicate or OOO partials FPDUs
145062306a36Sopenharmony_ci * @qp: qp ptr
145162306a36Sopenharmony_ci */
145262306a36Sopenharmony_civoid irdma_send_ieq_ack(struct irdma_sc_qp *qp)
145362306a36Sopenharmony_ci{
145462306a36Sopenharmony_ci	struct irdma_cm_node *cm_node = ((struct irdma_qp *)qp->qp_uk.back_qp)->cm_node;
145562306a36Sopenharmony_ci	struct irdma_puda_buf *buf = qp->pfpdu.lastrcv_buf;
145662306a36Sopenharmony_ci	struct tcphdr *tcph = (struct tcphdr *)buf->tcph;
145762306a36Sopenharmony_ci
145862306a36Sopenharmony_ci	cm_node->tcp_cntxt.rcv_nxt = qp->pfpdu.nextseqnum;
145962306a36Sopenharmony_ci	cm_node->tcp_cntxt.loc_seq_num = ntohl(tcph->ack_seq);
146062306a36Sopenharmony_ci
146162306a36Sopenharmony_ci	irdma_send_ack(cm_node);
146262306a36Sopenharmony_ci}
146362306a36Sopenharmony_ci
146462306a36Sopenharmony_ci/**
146562306a36Sopenharmony_ci * irdma_puda_ieq_get_ah_info - get AH info from IEQ buffer
146662306a36Sopenharmony_ci * @qp: qp pointer
146762306a36Sopenharmony_ci * @ah_info: AH info pointer
146862306a36Sopenharmony_ci */
146962306a36Sopenharmony_civoid irdma_puda_ieq_get_ah_info(struct irdma_sc_qp *qp,
147062306a36Sopenharmony_ci				struct irdma_ah_info *ah_info)
147162306a36Sopenharmony_ci{
147262306a36Sopenharmony_ci	struct irdma_puda_buf *buf = qp->pfpdu.ah_buf;
147362306a36Sopenharmony_ci	struct iphdr *iph;
147462306a36Sopenharmony_ci	struct ipv6hdr *ip6h;
147562306a36Sopenharmony_ci
147662306a36Sopenharmony_ci	memset(ah_info, 0, sizeof(*ah_info));
147762306a36Sopenharmony_ci	ah_info->do_lpbk = true;
147862306a36Sopenharmony_ci	ah_info->vlan_tag = buf->vlan_id;
147962306a36Sopenharmony_ci	ah_info->insert_vlan_tag = buf->vlan_valid;
148062306a36Sopenharmony_ci	ah_info->ipv4_valid = buf->ipv4;
148162306a36Sopenharmony_ci	ah_info->vsi = qp->vsi;
148262306a36Sopenharmony_ci
148362306a36Sopenharmony_ci	if (buf->smac_valid)
148462306a36Sopenharmony_ci		ether_addr_copy(ah_info->mac_addr, buf->smac);
148562306a36Sopenharmony_ci
148662306a36Sopenharmony_ci	if (buf->ipv4) {
148762306a36Sopenharmony_ci		ah_info->ipv4_valid = true;
148862306a36Sopenharmony_ci		iph = (struct iphdr *)buf->iph;
148962306a36Sopenharmony_ci		ah_info->hop_ttl = iph->ttl;
149062306a36Sopenharmony_ci		ah_info->tc_tos = iph->tos;
149162306a36Sopenharmony_ci		ah_info->dest_ip_addr[0] = ntohl(iph->daddr);
149262306a36Sopenharmony_ci		ah_info->src_ip_addr[0] = ntohl(iph->saddr);
149362306a36Sopenharmony_ci	} else {
149462306a36Sopenharmony_ci		ip6h = (struct ipv6hdr *)buf->iph;
149562306a36Sopenharmony_ci		ah_info->hop_ttl = ip6h->hop_limit;
149662306a36Sopenharmony_ci		ah_info->tc_tos = ip6h->priority;
149762306a36Sopenharmony_ci		irdma_copy_ip_ntohl(ah_info->dest_ip_addr,
149862306a36Sopenharmony_ci				    ip6h->daddr.in6_u.u6_addr32);
149962306a36Sopenharmony_ci		irdma_copy_ip_ntohl(ah_info->src_ip_addr,
150062306a36Sopenharmony_ci				    ip6h->saddr.in6_u.u6_addr32);
150162306a36Sopenharmony_ci	}
150262306a36Sopenharmony_ci
150362306a36Sopenharmony_ci	ah_info->dst_arpindex = irdma_arp_table(dev_to_rf(qp->dev),
150462306a36Sopenharmony_ci						ah_info->dest_ip_addr,
150562306a36Sopenharmony_ci						ah_info->ipv4_valid,
150662306a36Sopenharmony_ci						NULL, IRDMA_ARP_RESOLVE);
150762306a36Sopenharmony_ci}
150862306a36Sopenharmony_ci
150962306a36Sopenharmony_ci/**
151062306a36Sopenharmony_ci * irdma_gen1_ieq_update_tcpip_info - update tcpip in the buffer
151162306a36Sopenharmony_ci * @buf: puda to update
151262306a36Sopenharmony_ci * @len: length of buffer
151362306a36Sopenharmony_ci * @seqnum: seq number for tcp
151462306a36Sopenharmony_ci */
151562306a36Sopenharmony_cistatic void irdma_gen1_ieq_update_tcpip_info(struct irdma_puda_buf *buf,
151662306a36Sopenharmony_ci					     u16 len, u32 seqnum)
151762306a36Sopenharmony_ci{
151862306a36Sopenharmony_ci	struct tcphdr *tcph;
151962306a36Sopenharmony_ci	struct iphdr *iph;
152062306a36Sopenharmony_ci	u16 iphlen;
152162306a36Sopenharmony_ci	u16 pktsize;
152262306a36Sopenharmony_ci	u8 *addr = buf->mem.va;
152362306a36Sopenharmony_ci
152462306a36Sopenharmony_ci	iphlen = (buf->ipv4) ? 20 : 40;
152562306a36Sopenharmony_ci	iph = (struct iphdr *)(addr + buf->maclen);
152662306a36Sopenharmony_ci	tcph = (struct tcphdr *)(addr + buf->maclen + iphlen);
152762306a36Sopenharmony_ci	pktsize = len + buf->tcphlen + iphlen;
152862306a36Sopenharmony_ci	iph->tot_len = htons(pktsize);
152962306a36Sopenharmony_ci	tcph->seq = htonl(seqnum);
153062306a36Sopenharmony_ci}
153162306a36Sopenharmony_ci
153262306a36Sopenharmony_ci/**
153362306a36Sopenharmony_ci * irdma_ieq_update_tcpip_info - update tcpip in the buffer
153462306a36Sopenharmony_ci * @buf: puda to update
153562306a36Sopenharmony_ci * @len: length of buffer
153662306a36Sopenharmony_ci * @seqnum: seq number for tcp
153762306a36Sopenharmony_ci */
153862306a36Sopenharmony_civoid irdma_ieq_update_tcpip_info(struct irdma_puda_buf *buf, u16 len,
153962306a36Sopenharmony_ci				 u32 seqnum)
154062306a36Sopenharmony_ci{
154162306a36Sopenharmony_ci	struct tcphdr *tcph;
154262306a36Sopenharmony_ci	u8 *addr;
154362306a36Sopenharmony_ci
154462306a36Sopenharmony_ci	if (buf->vsi->dev->hw_attrs.uk_attrs.hw_rev == IRDMA_GEN_1)
154562306a36Sopenharmony_ci		return irdma_gen1_ieq_update_tcpip_info(buf, len, seqnum);
154662306a36Sopenharmony_ci
154762306a36Sopenharmony_ci	addr = buf->mem.va;
154862306a36Sopenharmony_ci	tcph = (struct tcphdr *)addr;
154962306a36Sopenharmony_ci	tcph->seq = htonl(seqnum);
155062306a36Sopenharmony_ci}
155162306a36Sopenharmony_ci
155262306a36Sopenharmony_ci/**
155362306a36Sopenharmony_ci * irdma_gen1_puda_get_tcpip_info - get tcpip info from puda
155462306a36Sopenharmony_ci * buffer
155562306a36Sopenharmony_ci * @info: to get information
155662306a36Sopenharmony_ci * @buf: puda buffer
155762306a36Sopenharmony_ci */
155862306a36Sopenharmony_cistatic int irdma_gen1_puda_get_tcpip_info(struct irdma_puda_cmpl_info *info,
155962306a36Sopenharmony_ci					  struct irdma_puda_buf *buf)
156062306a36Sopenharmony_ci{
156162306a36Sopenharmony_ci	struct iphdr *iph;
156262306a36Sopenharmony_ci	struct ipv6hdr *ip6h;
156362306a36Sopenharmony_ci	struct tcphdr *tcph;
156462306a36Sopenharmony_ci	u16 iphlen;
156562306a36Sopenharmony_ci	u16 pkt_len;
156662306a36Sopenharmony_ci	u8 *mem = buf->mem.va;
156762306a36Sopenharmony_ci	struct ethhdr *ethh = buf->mem.va;
156862306a36Sopenharmony_ci
156962306a36Sopenharmony_ci	if (ethh->h_proto == htons(0x8100)) {
157062306a36Sopenharmony_ci		info->vlan_valid = true;
157162306a36Sopenharmony_ci		buf->vlan_id = ntohs(((struct vlan_ethhdr *)ethh)->h_vlan_TCI) &
157262306a36Sopenharmony_ci			       VLAN_VID_MASK;
157362306a36Sopenharmony_ci	}
157462306a36Sopenharmony_ci
157562306a36Sopenharmony_ci	buf->maclen = (info->vlan_valid) ? 18 : 14;
157662306a36Sopenharmony_ci	iphlen = (info->l3proto) ? 40 : 20;
157762306a36Sopenharmony_ci	buf->ipv4 = (info->l3proto) ? false : true;
157862306a36Sopenharmony_ci	buf->iph = mem + buf->maclen;
157962306a36Sopenharmony_ci	iph = (struct iphdr *)buf->iph;
158062306a36Sopenharmony_ci	buf->tcph = buf->iph + iphlen;
158162306a36Sopenharmony_ci	tcph = (struct tcphdr *)buf->tcph;
158262306a36Sopenharmony_ci
158362306a36Sopenharmony_ci	if (buf->ipv4) {
158462306a36Sopenharmony_ci		pkt_len = ntohs(iph->tot_len);
158562306a36Sopenharmony_ci	} else {
158662306a36Sopenharmony_ci		ip6h = (struct ipv6hdr *)buf->iph;
158762306a36Sopenharmony_ci		pkt_len = ntohs(ip6h->payload_len) + iphlen;
158862306a36Sopenharmony_ci	}
158962306a36Sopenharmony_ci
159062306a36Sopenharmony_ci	buf->totallen = pkt_len + buf->maclen;
159162306a36Sopenharmony_ci
159262306a36Sopenharmony_ci	if (info->payload_len < buf->totallen) {
159362306a36Sopenharmony_ci		ibdev_dbg(to_ibdev(buf->vsi->dev),
159462306a36Sopenharmony_ci			  "ERR: payload_len = 0x%x totallen expected0x%x\n",
159562306a36Sopenharmony_ci			  info->payload_len, buf->totallen);
159662306a36Sopenharmony_ci		return -EINVAL;
159762306a36Sopenharmony_ci	}
159862306a36Sopenharmony_ci
159962306a36Sopenharmony_ci	buf->tcphlen = tcph->doff << 2;
160062306a36Sopenharmony_ci	buf->datalen = pkt_len - iphlen - buf->tcphlen;
160162306a36Sopenharmony_ci	buf->data = buf->datalen ? buf->tcph + buf->tcphlen : NULL;
160262306a36Sopenharmony_ci	buf->hdrlen = buf->maclen + iphlen + buf->tcphlen;
160362306a36Sopenharmony_ci	buf->seqnum = ntohl(tcph->seq);
160462306a36Sopenharmony_ci
160562306a36Sopenharmony_ci	return 0;
160662306a36Sopenharmony_ci}
160762306a36Sopenharmony_ci
160862306a36Sopenharmony_ci/**
160962306a36Sopenharmony_ci * irdma_puda_get_tcpip_info - get tcpip info from puda buffer
161062306a36Sopenharmony_ci * @info: to get information
161162306a36Sopenharmony_ci * @buf: puda buffer
161262306a36Sopenharmony_ci */
161362306a36Sopenharmony_ciint irdma_puda_get_tcpip_info(struct irdma_puda_cmpl_info *info,
161462306a36Sopenharmony_ci			      struct irdma_puda_buf *buf)
161562306a36Sopenharmony_ci{
161662306a36Sopenharmony_ci	struct tcphdr *tcph;
161762306a36Sopenharmony_ci	u32 pkt_len;
161862306a36Sopenharmony_ci	u8 *mem;
161962306a36Sopenharmony_ci
162062306a36Sopenharmony_ci	if (buf->vsi->dev->hw_attrs.uk_attrs.hw_rev == IRDMA_GEN_1)
162162306a36Sopenharmony_ci		return irdma_gen1_puda_get_tcpip_info(info, buf);
162262306a36Sopenharmony_ci
162362306a36Sopenharmony_ci	mem = buf->mem.va;
162462306a36Sopenharmony_ci	buf->vlan_valid = info->vlan_valid;
162562306a36Sopenharmony_ci	if (info->vlan_valid)
162662306a36Sopenharmony_ci		buf->vlan_id = info->vlan;
162762306a36Sopenharmony_ci
162862306a36Sopenharmony_ci	buf->ipv4 = info->ipv4;
162962306a36Sopenharmony_ci	if (buf->ipv4)
163062306a36Sopenharmony_ci		buf->iph = mem + IRDMA_IPV4_PAD;
163162306a36Sopenharmony_ci	else
163262306a36Sopenharmony_ci		buf->iph = mem;
163362306a36Sopenharmony_ci
163462306a36Sopenharmony_ci	buf->tcph = mem + IRDMA_TCP_OFFSET;
163562306a36Sopenharmony_ci	tcph = (struct tcphdr *)buf->tcph;
163662306a36Sopenharmony_ci	pkt_len = info->payload_len;
163762306a36Sopenharmony_ci	buf->totallen = pkt_len;
163862306a36Sopenharmony_ci	buf->tcphlen = tcph->doff << 2;
163962306a36Sopenharmony_ci	buf->datalen = pkt_len - IRDMA_TCP_OFFSET - buf->tcphlen;
164062306a36Sopenharmony_ci	buf->data = buf->datalen ? buf->tcph + buf->tcphlen : NULL;
164162306a36Sopenharmony_ci	buf->hdrlen = IRDMA_TCP_OFFSET + buf->tcphlen;
164262306a36Sopenharmony_ci	buf->seqnum = ntohl(tcph->seq);
164362306a36Sopenharmony_ci
164462306a36Sopenharmony_ci	if (info->smac_valid) {
164562306a36Sopenharmony_ci		ether_addr_copy(buf->smac, info->smac);
164662306a36Sopenharmony_ci		buf->smac_valid = true;
164762306a36Sopenharmony_ci	}
164862306a36Sopenharmony_ci
164962306a36Sopenharmony_ci	return 0;
165062306a36Sopenharmony_ci}
165162306a36Sopenharmony_ci
165262306a36Sopenharmony_ci/**
165362306a36Sopenharmony_ci * irdma_hw_stats_timeout - Stats timer-handler which updates all HW stats
165462306a36Sopenharmony_ci * @t: timer_list pointer
165562306a36Sopenharmony_ci */
165662306a36Sopenharmony_cistatic void irdma_hw_stats_timeout(struct timer_list *t)
165762306a36Sopenharmony_ci{
165862306a36Sopenharmony_ci	struct irdma_vsi_pestat *pf_devstat =
165962306a36Sopenharmony_ci		from_timer(pf_devstat, t, stats_timer);
166062306a36Sopenharmony_ci	struct irdma_sc_vsi *sc_vsi = pf_devstat->vsi;
166162306a36Sopenharmony_ci
166262306a36Sopenharmony_ci	if (sc_vsi->dev->hw_attrs.uk_attrs.hw_rev >= IRDMA_GEN_2)
166362306a36Sopenharmony_ci		irdma_cqp_gather_stats_cmd(sc_vsi->dev, sc_vsi->pestat, false);
166462306a36Sopenharmony_ci	else
166562306a36Sopenharmony_ci		irdma_cqp_gather_stats_gen1(sc_vsi->dev, sc_vsi->pestat);
166662306a36Sopenharmony_ci
166762306a36Sopenharmony_ci	mod_timer(&pf_devstat->stats_timer,
166862306a36Sopenharmony_ci		  jiffies + msecs_to_jiffies(STATS_TIMER_DELAY));
166962306a36Sopenharmony_ci}
167062306a36Sopenharmony_ci
167162306a36Sopenharmony_ci/**
167262306a36Sopenharmony_ci * irdma_hw_stats_start_timer - Start periodic stats timer
167362306a36Sopenharmony_ci * @vsi: vsi structure pointer
167462306a36Sopenharmony_ci */
167562306a36Sopenharmony_civoid irdma_hw_stats_start_timer(struct irdma_sc_vsi *vsi)
167662306a36Sopenharmony_ci{
167762306a36Sopenharmony_ci	struct irdma_vsi_pestat *devstat = vsi->pestat;
167862306a36Sopenharmony_ci
167962306a36Sopenharmony_ci	timer_setup(&devstat->stats_timer, irdma_hw_stats_timeout, 0);
168062306a36Sopenharmony_ci	mod_timer(&devstat->stats_timer,
168162306a36Sopenharmony_ci		  jiffies + msecs_to_jiffies(STATS_TIMER_DELAY));
168262306a36Sopenharmony_ci}
168362306a36Sopenharmony_ci
168462306a36Sopenharmony_ci/**
168562306a36Sopenharmony_ci * irdma_hw_stats_stop_timer - Delete periodic stats timer
168662306a36Sopenharmony_ci * @vsi: pointer to vsi structure
168762306a36Sopenharmony_ci */
168862306a36Sopenharmony_civoid irdma_hw_stats_stop_timer(struct irdma_sc_vsi *vsi)
168962306a36Sopenharmony_ci{
169062306a36Sopenharmony_ci	struct irdma_vsi_pestat *devstat = vsi->pestat;
169162306a36Sopenharmony_ci
169262306a36Sopenharmony_ci	del_timer_sync(&devstat->stats_timer);
169362306a36Sopenharmony_ci}
169462306a36Sopenharmony_ci
169562306a36Sopenharmony_ci/**
169662306a36Sopenharmony_ci * irdma_process_stats - Checking for wrap and update stats
169762306a36Sopenharmony_ci * @pestat: stats structure pointer
169862306a36Sopenharmony_ci */
169962306a36Sopenharmony_cistatic inline void irdma_process_stats(struct irdma_vsi_pestat *pestat)
170062306a36Sopenharmony_ci{
170162306a36Sopenharmony_ci	sc_vsi_update_stats(pestat->vsi);
170262306a36Sopenharmony_ci}
170362306a36Sopenharmony_ci
170462306a36Sopenharmony_ci/**
170562306a36Sopenharmony_ci * irdma_cqp_gather_stats_gen1 - Gather stats
170662306a36Sopenharmony_ci * @dev: pointer to device structure
170762306a36Sopenharmony_ci * @pestat: statistics structure
170862306a36Sopenharmony_ci */
170962306a36Sopenharmony_civoid irdma_cqp_gather_stats_gen1(struct irdma_sc_dev *dev,
171062306a36Sopenharmony_ci				 struct irdma_vsi_pestat *pestat)
171162306a36Sopenharmony_ci{
171262306a36Sopenharmony_ci	struct irdma_gather_stats *gather_stats =
171362306a36Sopenharmony_ci		pestat->gather_info.gather_stats_va;
171462306a36Sopenharmony_ci	const struct irdma_hw_stat_map *map = dev->hw_stats_map;
171562306a36Sopenharmony_ci	u16 max_stats_idx = dev->hw_attrs.max_stat_idx;
171662306a36Sopenharmony_ci	u32 stats_inst_offset_32;
171762306a36Sopenharmony_ci	u32 stats_inst_offset_64;
171862306a36Sopenharmony_ci	u64 new_val;
171962306a36Sopenharmony_ci	u16 i;
172062306a36Sopenharmony_ci
172162306a36Sopenharmony_ci	stats_inst_offset_32 = (pestat->gather_info.use_stats_inst) ?
172262306a36Sopenharmony_ci				pestat->gather_info.stats_inst_index :
172362306a36Sopenharmony_ci				pestat->hw->hmc.hmc_fn_id;
172462306a36Sopenharmony_ci	stats_inst_offset_32 *= 4;
172562306a36Sopenharmony_ci	stats_inst_offset_64 = stats_inst_offset_32 * 2;
172662306a36Sopenharmony_ci
172762306a36Sopenharmony_ci	for (i = 0; i < max_stats_idx; i++) {
172862306a36Sopenharmony_ci		if (map[i].bitmask <= IRDMA_MAX_STATS_32)
172962306a36Sopenharmony_ci			new_val = rd32(dev->hw,
173062306a36Sopenharmony_ci				       dev->hw_stats_regs[i] + stats_inst_offset_32);
173162306a36Sopenharmony_ci		else
173262306a36Sopenharmony_ci			new_val = rd64(dev->hw,
173362306a36Sopenharmony_ci				       dev->hw_stats_regs[i] + stats_inst_offset_64);
173462306a36Sopenharmony_ci		gather_stats->val[map[i].byteoff / sizeof(u64)] = new_val;
173562306a36Sopenharmony_ci	}
173662306a36Sopenharmony_ci
173762306a36Sopenharmony_ci	irdma_process_stats(pestat);
173862306a36Sopenharmony_ci}
173962306a36Sopenharmony_ci
174062306a36Sopenharmony_ci/**
174162306a36Sopenharmony_ci * irdma_process_cqp_stats - Checking for wrap and update stats
174262306a36Sopenharmony_ci * @cqp_request: cqp_request structure pointer
174362306a36Sopenharmony_ci */
174462306a36Sopenharmony_cistatic void irdma_process_cqp_stats(struct irdma_cqp_request *cqp_request)
174562306a36Sopenharmony_ci{
174662306a36Sopenharmony_ci	struct irdma_vsi_pestat *pestat = cqp_request->param;
174762306a36Sopenharmony_ci
174862306a36Sopenharmony_ci	irdma_process_stats(pestat);
174962306a36Sopenharmony_ci}
175062306a36Sopenharmony_ci
175162306a36Sopenharmony_ci/**
175262306a36Sopenharmony_ci * irdma_cqp_gather_stats_cmd - Gather stats
175362306a36Sopenharmony_ci * @dev: pointer to device structure
175462306a36Sopenharmony_ci * @pestat: pointer to stats info
175562306a36Sopenharmony_ci * @wait: flag to wait or not wait for stats
175662306a36Sopenharmony_ci */
175762306a36Sopenharmony_ciint irdma_cqp_gather_stats_cmd(struct irdma_sc_dev *dev,
175862306a36Sopenharmony_ci			       struct irdma_vsi_pestat *pestat, bool wait)
175962306a36Sopenharmony_ci
176062306a36Sopenharmony_ci{
176162306a36Sopenharmony_ci	struct irdma_pci_f *rf = dev_to_rf(dev);
176262306a36Sopenharmony_ci	struct irdma_cqp *iwcqp = &rf->cqp;
176362306a36Sopenharmony_ci	struct irdma_cqp_request *cqp_request;
176462306a36Sopenharmony_ci	struct cqp_cmds_info *cqp_info;
176562306a36Sopenharmony_ci	int status;
176662306a36Sopenharmony_ci
176762306a36Sopenharmony_ci	cqp_request = irdma_alloc_and_get_cqp_request(iwcqp, wait);
176862306a36Sopenharmony_ci	if (!cqp_request)
176962306a36Sopenharmony_ci		return -ENOMEM;
177062306a36Sopenharmony_ci
177162306a36Sopenharmony_ci	cqp_info = &cqp_request->info;
177262306a36Sopenharmony_ci	memset(cqp_info, 0, sizeof(*cqp_info));
177362306a36Sopenharmony_ci	cqp_info->cqp_cmd = IRDMA_OP_STATS_GATHER;
177462306a36Sopenharmony_ci	cqp_info->post_sq = 1;
177562306a36Sopenharmony_ci	cqp_info->in.u.stats_gather.info = pestat->gather_info;
177662306a36Sopenharmony_ci	cqp_info->in.u.stats_gather.scratch = (uintptr_t)cqp_request;
177762306a36Sopenharmony_ci	cqp_info->in.u.stats_gather.cqp = &rf->cqp.sc_cqp;
177862306a36Sopenharmony_ci	cqp_request->param = pestat;
177962306a36Sopenharmony_ci	if (!wait)
178062306a36Sopenharmony_ci		cqp_request->callback_fcn = irdma_process_cqp_stats;
178162306a36Sopenharmony_ci	status = irdma_handle_cqp_op(rf, cqp_request);
178262306a36Sopenharmony_ci	if (wait)
178362306a36Sopenharmony_ci		irdma_process_stats(pestat);
178462306a36Sopenharmony_ci	irdma_put_cqp_request(&rf->cqp, cqp_request);
178562306a36Sopenharmony_ci
178662306a36Sopenharmony_ci	return status;
178762306a36Sopenharmony_ci}
178862306a36Sopenharmony_ci
178962306a36Sopenharmony_ci/**
179062306a36Sopenharmony_ci * irdma_cqp_stats_inst_cmd - Allocate/free stats instance
179162306a36Sopenharmony_ci * @vsi: pointer to vsi structure
179262306a36Sopenharmony_ci * @cmd: command to allocate or free
179362306a36Sopenharmony_ci * @stats_info: pointer to allocate stats info
179462306a36Sopenharmony_ci */
179562306a36Sopenharmony_ciint irdma_cqp_stats_inst_cmd(struct irdma_sc_vsi *vsi, u8 cmd,
179662306a36Sopenharmony_ci			     struct irdma_stats_inst_info *stats_info)
179762306a36Sopenharmony_ci{
179862306a36Sopenharmony_ci	struct irdma_pci_f *rf = dev_to_rf(vsi->dev);
179962306a36Sopenharmony_ci	struct irdma_cqp *iwcqp = &rf->cqp;
180062306a36Sopenharmony_ci	struct irdma_cqp_request *cqp_request;
180162306a36Sopenharmony_ci	struct cqp_cmds_info *cqp_info;
180262306a36Sopenharmony_ci	int status;
180362306a36Sopenharmony_ci	bool wait = false;
180462306a36Sopenharmony_ci
180562306a36Sopenharmony_ci	if (cmd == IRDMA_OP_STATS_ALLOCATE)
180662306a36Sopenharmony_ci		wait = true;
180762306a36Sopenharmony_ci	cqp_request = irdma_alloc_and_get_cqp_request(iwcqp, wait);
180862306a36Sopenharmony_ci	if (!cqp_request)
180962306a36Sopenharmony_ci		return -ENOMEM;
181062306a36Sopenharmony_ci
181162306a36Sopenharmony_ci	cqp_info = &cqp_request->info;
181262306a36Sopenharmony_ci	memset(cqp_info, 0, sizeof(*cqp_info));
181362306a36Sopenharmony_ci	cqp_info->cqp_cmd = cmd;
181462306a36Sopenharmony_ci	cqp_info->post_sq = 1;
181562306a36Sopenharmony_ci	cqp_info->in.u.stats_manage.info = *stats_info;
181662306a36Sopenharmony_ci	cqp_info->in.u.stats_manage.scratch = (uintptr_t)cqp_request;
181762306a36Sopenharmony_ci	cqp_info->in.u.stats_manage.cqp = &rf->cqp.sc_cqp;
181862306a36Sopenharmony_ci	status = irdma_handle_cqp_op(rf, cqp_request);
181962306a36Sopenharmony_ci	if (wait)
182062306a36Sopenharmony_ci		stats_info->stats_idx = cqp_request->compl_info.op_ret_val;
182162306a36Sopenharmony_ci	irdma_put_cqp_request(iwcqp, cqp_request);
182262306a36Sopenharmony_ci
182362306a36Sopenharmony_ci	return status;
182462306a36Sopenharmony_ci}
182562306a36Sopenharmony_ci
182662306a36Sopenharmony_ci/**
182762306a36Sopenharmony_ci * irdma_cqp_ceq_cmd - Create/Destroy CEQ's after CEQ 0
182862306a36Sopenharmony_ci * @dev: pointer to device info
182962306a36Sopenharmony_ci * @sc_ceq: pointer to ceq structure
183062306a36Sopenharmony_ci * @op: Create or Destroy
183162306a36Sopenharmony_ci */
183262306a36Sopenharmony_ciint irdma_cqp_ceq_cmd(struct irdma_sc_dev *dev, struct irdma_sc_ceq *sc_ceq,
183362306a36Sopenharmony_ci		      u8 op)
183462306a36Sopenharmony_ci{
183562306a36Sopenharmony_ci	struct irdma_cqp_request *cqp_request;
183662306a36Sopenharmony_ci	struct cqp_cmds_info *cqp_info;
183762306a36Sopenharmony_ci	struct irdma_pci_f *rf = dev_to_rf(dev);
183862306a36Sopenharmony_ci	int status;
183962306a36Sopenharmony_ci
184062306a36Sopenharmony_ci	cqp_request = irdma_alloc_and_get_cqp_request(&rf->cqp, true);
184162306a36Sopenharmony_ci	if (!cqp_request)
184262306a36Sopenharmony_ci		return -ENOMEM;
184362306a36Sopenharmony_ci
184462306a36Sopenharmony_ci	cqp_info = &cqp_request->info;
184562306a36Sopenharmony_ci	cqp_info->post_sq = 1;
184662306a36Sopenharmony_ci	cqp_info->cqp_cmd = op;
184762306a36Sopenharmony_ci	cqp_info->in.u.ceq_create.ceq = sc_ceq;
184862306a36Sopenharmony_ci	cqp_info->in.u.ceq_create.scratch = (uintptr_t)cqp_request;
184962306a36Sopenharmony_ci
185062306a36Sopenharmony_ci	status = irdma_handle_cqp_op(rf, cqp_request);
185162306a36Sopenharmony_ci	irdma_put_cqp_request(&rf->cqp, cqp_request);
185262306a36Sopenharmony_ci
185362306a36Sopenharmony_ci	return status;
185462306a36Sopenharmony_ci}
185562306a36Sopenharmony_ci
185662306a36Sopenharmony_ci/**
185762306a36Sopenharmony_ci * irdma_cqp_aeq_cmd - Create/Destroy AEQ
185862306a36Sopenharmony_ci * @dev: pointer to device info
185962306a36Sopenharmony_ci * @sc_aeq: pointer to aeq structure
186062306a36Sopenharmony_ci * @op: Create or Destroy
186162306a36Sopenharmony_ci */
186262306a36Sopenharmony_ciint irdma_cqp_aeq_cmd(struct irdma_sc_dev *dev, struct irdma_sc_aeq *sc_aeq,
186362306a36Sopenharmony_ci		      u8 op)
186462306a36Sopenharmony_ci{
186562306a36Sopenharmony_ci	struct irdma_cqp_request *cqp_request;
186662306a36Sopenharmony_ci	struct cqp_cmds_info *cqp_info;
186762306a36Sopenharmony_ci	struct irdma_pci_f *rf = dev_to_rf(dev);
186862306a36Sopenharmony_ci	int status;
186962306a36Sopenharmony_ci
187062306a36Sopenharmony_ci	cqp_request = irdma_alloc_and_get_cqp_request(&rf->cqp, true);
187162306a36Sopenharmony_ci	if (!cqp_request)
187262306a36Sopenharmony_ci		return -ENOMEM;
187362306a36Sopenharmony_ci
187462306a36Sopenharmony_ci	cqp_info = &cqp_request->info;
187562306a36Sopenharmony_ci	cqp_info->post_sq = 1;
187662306a36Sopenharmony_ci	cqp_info->cqp_cmd = op;
187762306a36Sopenharmony_ci	cqp_info->in.u.aeq_create.aeq = sc_aeq;
187862306a36Sopenharmony_ci	cqp_info->in.u.aeq_create.scratch = (uintptr_t)cqp_request;
187962306a36Sopenharmony_ci
188062306a36Sopenharmony_ci	status = irdma_handle_cqp_op(rf, cqp_request);
188162306a36Sopenharmony_ci	irdma_put_cqp_request(&rf->cqp, cqp_request);
188262306a36Sopenharmony_ci
188362306a36Sopenharmony_ci	return status;
188462306a36Sopenharmony_ci}
188562306a36Sopenharmony_ci
188662306a36Sopenharmony_ci/**
188762306a36Sopenharmony_ci * irdma_cqp_ws_node_cmd - Add/modify/delete ws node
188862306a36Sopenharmony_ci * @dev: pointer to device structure
188962306a36Sopenharmony_ci * @cmd: Add, modify or delete
189062306a36Sopenharmony_ci * @node_info: pointer to ws node info
189162306a36Sopenharmony_ci */
189262306a36Sopenharmony_ciint irdma_cqp_ws_node_cmd(struct irdma_sc_dev *dev, u8 cmd,
189362306a36Sopenharmony_ci			  struct irdma_ws_node_info *node_info)
189462306a36Sopenharmony_ci{
189562306a36Sopenharmony_ci	struct irdma_pci_f *rf = dev_to_rf(dev);
189662306a36Sopenharmony_ci	struct irdma_cqp *iwcqp = &rf->cqp;
189762306a36Sopenharmony_ci	struct irdma_sc_cqp *cqp = &iwcqp->sc_cqp;
189862306a36Sopenharmony_ci	struct irdma_cqp_request *cqp_request;
189962306a36Sopenharmony_ci	struct cqp_cmds_info *cqp_info;
190062306a36Sopenharmony_ci	int status;
190162306a36Sopenharmony_ci	bool poll;
190262306a36Sopenharmony_ci
190362306a36Sopenharmony_ci	if (!rf->sc_dev.ceq_valid)
190462306a36Sopenharmony_ci		poll = true;
190562306a36Sopenharmony_ci	else
190662306a36Sopenharmony_ci		poll = false;
190762306a36Sopenharmony_ci
190862306a36Sopenharmony_ci	cqp_request = irdma_alloc_and_get_cqp_request(iwcqp, !poll);
190962306a36Sopenharmony_ci	if (!cqp_request)
191062306a36Sopenharmony_ci		return -ENOMEM;
191162306a36Sopenharmony_ci
191262306a36Sopenharmony_ci	cqp_info = &cqp_request->info;
191362306a36Sopenharmony_ci	memset(cqp_info, 0, sizeof(*cqp_info));
191462306a36Sopenharmony_ci	cqp_info->cqp_cmd = cmd;
191562306a36Sopenharmony_ci	cqp_info->post_sq = 1;
191662306a36Sopenharmony_ci	cqp_info->in.u.ws_node.info = *node_info;
191762306a36Sopenharmony_ci	cqp_info->in.u.ws_node.cqp = cqp;
191862306a36Sopenharmony_ci	cqp_info->in.u.ws_node.scratch = (uintptr_t)cqp_request;
191962306a36Sopenharmony_ci	status = irdma_handle_cqp_op(rf, cqp_request);
192062306a36Sopenharmony_ci	if (status)
192162306a36Sopenharmony_ci		goto exit;
192262306a36Sopenharmony_ci
192362306a36Sopenharmony_ci	if (poll) {
192462306a36Sopenharmony_ci		struct irdma_ccq_cqe_info compl_info;
192562306a36Sopenharmony_ci
192662306a36Sopenharmony_ci		status = irdma_sc_poll_for_cqp_op_done(cqp, IRDMA_CQP_OP_WORK_SCHED_NODE,
192762306a36Sopenharmony_ci						       &compl_info);
192862306a36Sopenharmony_ci		node_info->qs_handle = compl_info.op_ret_val;
192962306a36Sopenharmony_ci		ibdev_dbg(&rf->iwdev->ibdev, "DCB: opcode=%d, compl_info.retval=%d\n",
193062306a36Sopenharmony_ci			  compl_info.op_code, compl_info.op_ret_val);
193162306a36Sopenharmony_ci	} else {
193262306a36Sopenharmony_ci		node_info->qs_handle = cqp_request->compl_info.op_ret_val;
193362306a36Sopenharmony_ci	}
193462306a36Sopenharmony_ci
193562306a36Sopenharmony_ciexit:
193662306a36Sopenharmony_ci	irdma_put_cqp_request(&rf->cqp, cqp_request);
193762306a36Sopenharmony_ci
193862306a36Sopenharmony_ci	return status;
193962306a36Sopenharmony_ci}
194062306a36Sopenharmony_ci
194162306a36Sopenharmony_ci/**
194262306a36Sopenharmony_ci * irdma_ah_cqp_op - perform an AH cqp operation
194362306a36Sopenharmony_ci * @rf: RDMA PCI function
194462306a36Sopenharmony_ci * @sc_ah: address handle
194562306a36Sopenharmony_ci * @cmd: AH operation
194662306a36Sopenharmony_ci * @wait: wait if true
194762306a36Sopenharmony_ci * @callback_fcn: Callback function on CQP op completion
194862306a36Sopenharmony_ci * @cb_param: parameter for callback function
194962306a36Sopenharmony_ci *
195062306a36Sopenharmony_ci * returns errno
195162306a36Sopenharmony_ci */
195262306a36Sopenharmony_ciint irdma_ah_cqp_op(struct irdma_pci_f *rf, struct irdma_sc_ah *sc_ah, u8 cmd,
195362306a36Sopenharmony_ci		    bool wait,
195462306a36Sopenharmony_ci		    void (*callback_fcn)(struct irdma_cqp_request *),
195562306a36Sopenharmony_ci		    void *cb_param)
195662306a36Sopenharmony_ci{
195762306a36Sopenharmony_ci	struct irdma_cqp_request *cqp_request;
195862306a36Sopenharmony_ci	struct cqp_cmds_info *cqp_info;
195962306a36Sopenharmony_ci	int status;
196062306a36Sopenharmony_ci
196162306a36Sopenharmony_ci	if (cmd != IRDMA_OP_AH_CREATE && cmd != IRDMA_OP_AH_DESTROY)
196262306a36Sopenharmony_ci		return -EINVAL;
196362306a36Sopenharmony_ci
196462306a36Sopenharmony_ci	cqp_request = irdma_alloc_and_get_cqp_request(&rf->cqp, wait);
196562306a36Sopenharmony_ci	if (!cqp_request)
196662306a36Sopenharmony_ci		return -ENOMEM;
196762306a36Sopenharmony_ci
196862306a36Sopenharmony_ci	cqp_info = &cqp_request->info;
196962306a36Sopenharmony_ci	cqp_info->cqp_cmd = cmd;
197062306a36Sopenharmony_ci	cqp_info->post_sq = 1;
197162306a36Sopenharmony_ci	if (cmd == IRDMA_OP_AH_CREATE) {
197262306a36Sopenharmony_ci		cqp_info->in.u.ah_create.info = sc_ah->ah_info;
197362306a36Sopenharmony_ci		cqp_info->in.u.ah_create.scratch = (uintptr_t)cqp_request;
197462306a36Sopenharmony_ci		cqp_info->in.u.ah_create.cqp = &rf->cqp.sc_cqp;
197562306a36Sopenharmony_ci	} else if (cmd == IRDMA_OP_AH_DESTROY) {
197662306a36Sopenharmony_ci		cqp_info->in.u.ah_destroy.info = sc_ah->ah_info;
197762306a36Sopenharmony_ci		cqp_info->in.u.ah_destroy.scratch = (uintptr_t)cqp_request;
197862306a36Sopenharmony_ci		cqp_info->in.u.ah_destroy.cqp = &rf->cqp.sc_cqp;
197962306a36Sopenharmony_ci	}
198062306a36Sopenharmony_ci
198162306a36Sopenharmony_ci	if (!wait) {
198262306a36Sopenharmony_ci		cqp_request->callback_fcn = callback_fcn;
198362306a36Sopenharmony_ci		cqp_request->param = cb_param;
198462306a36Sopenharmony_ci	}
198562306a36Sopenharmony_ci	status = irdma_handle_cqp_op(rf, cqp_request);
198662306a36Sopenharmony_ci	irdma_put_cqp_request(&rf->cqp, cqp_request);
198762306a36Sopenharmony_ci
198862306a36Sopenharmony_ci	if (status)
198962306a36Sopenharmony_ci		return -ENOMEM;
199062306a36Sopenharmony_ci
199162306a36Sopenharmony_ci	if (wait)
199262306a36Sopenharmony_ci		sc_ah->ah_info.ah_valid = (cmd == IRDMA_OP_AH_CREATE);
199362306a36Sopenharmony_ci
199462306a36Sopenharmony_ci	return 0;
199562306a36Sopenharmony_ci}
199662306a36Sopenharmony_ci
199762306a36Sopenharmony_ci/**
199862306a36Sopenharmony_ci * irdma_ieq_ah_cb - callback after creation of AH for IEQ
199962306a36Sopenharmony_ci * @cqp_request: pointer to cqp_request of create AH
200062306a36Sopenharmony_ci */
200162306a36Sopenharmony_cistatic void irdma_ieq_ah_cb(struct irdma_cqp_request *cqp_request)
200262306a36Sopenharmony_ci{
200362306a36Sopenharmony_ci	struct irdma_sc_qp *qp = cqp_request->param;
200462306a36Sopenharmony_ci	struct irdma_sc_ah *sc_ah = qp->pfpdu.ah;
200562306a36Sopenharmony_ci	unsigned long flags;
200662306a36Sopenharmony_ci
200762306a36Sopenharmony_ci	spin_lock_irqsave(&qp->pfpdu.lock, flags);
200862306a36Sopenharmony_ci	if (!cqp_request->compl_info.op_ret_val) {
200962306a36Sopenharmony_ci		sc_ah->ah_info.ah_valid = true;
201062306a36Sopenharmony_ci		irdma_ieq_process_fpdus(qp, qp->vsi->ieq);
201162306a36Sopenharmony_ci	} else {
201262306a36Sopenharmony_ci		sc_ah->ah_info.ah_valid = false;
201362306a36Sopenharmony_ci		irdma_ieq_cleanup_qp(qp->vsi->ieq, qp);
201462306a36Sopenharmony_ci	}
201562306a36Sopenharmony_ci	spin_unlock_irqrestore(&qp->pfpdu.lock, flags);
201662306a36Sopenharmony_ci}
201762306a36Sopenharmony_ci
201862306a36Sopenharmony_ci/**
201962306a36Sopenharmony_ci * irdma_ilq_ah_cb - callback after creation of AH for ILQ
202062306a36Sopenharmony_ci * @cqp_request: pointer to cqp_request of create AH
202162306a36Sopenharmony_ci */
202262306a36Sopenharmony_cistatic void irdma_ilq_ah_cb(struct irdma_cqp_request *cqp_request)
202362306a36Sopenharmony_ci{
202462306a36Sopenharmony_ci	struct irdma_cm_node *cm_node = cqp_request->param;
202562306a36Sopenharmony_ci	struct irdma_sc_ah *sc_ah = cm_node->ah;
202662306a36Sopenharmony_ci
202762306a36Sopenharmony_ci	sc_ah->ah_info.ah_valid = !cqp_request->compl_info.op_ret_val;
202862306a36Sopenharmony_ci	irdma_add_conn_est_qh(cm_node);
202962306a36Sopenharmony_ci}
203062306a36Sopenharmony_ci
203162306a36Sopenharmony_ci/**
203262306a36Sopenharmony_ci * irdma_puda_create_ah - create AH for ILQ/IEQ qp's
203362306a36Sopenharmony_ci * @dev: device pointer
203462306a36Sopenharmony_ci * @ah_info: Address handle info
203562306a36Sopenharmony_ci * @wait: When true will wait for operation to complete
203662306a36Sopenharmony_ci * @type: ILQ/IEQ
203762306a36Sopenharmony_ci * @cb_param: Callback param when not waiting
203862306a36Sopenharmony_ci * @ah_ret: Returned pointer to address handle if created
203962306a36Sopenharmony_ci *
204062306a36Sopenharmony_ci */
204162306a36Sopenharmony_ciint irdma_puda_create_ah(struct irdma_sc_dev *dev,
204262306a36Sopenharmony_ci			 struct irdma_ah_info *ah_info, bool wait,
204362306a36Sopenharmony_ci			 enum puda_rsrc_type type, void *cb_param,
204462306a36Sopenharmony_ci			 struct irdma_sc_ah **ah_ret)
204562306a36Sopenharmony_ci{
204662306a36Sopenharmony_ci	struct irdma_sc_ah *ah;
204762306a36Sopenharmony_ci	struct irdma_pci_f *rf = dev_to_rf(dev);
204862306a36Sopenharmony_ci	int err;
204962306a36Sopenharmony_ci
205062306a36Sopenharmony_ci	ah = kzalloc(sizeof(*ah), GFP_ATOMIC);
205162306a36Sopenharmony_ci	*ah_ret = ah;
205262306a36Sopenharmony_ci	if (!ah)
205362306a36Sopenharmony_ci		return -ENOMEM;
205462306a36Sopenharmony_ci
205562306a36Sopenharmony_ci	err = irdma_alloc_rsrc(rf, rf->allocated_ahs, rf->max_ah,
205662306a36Sopenharmony_ci			       &ah_info->ah_idx, &rf->next_ah);
205762306a36Sopenharmony_ci	if (err)
205862306a36Sopenharmony_ci		goto err_free;
205962306a36Sopenharmony_ci
206062306a36Sopenharmony_ci	ah->dev = dev;
206162306a36Sopenharmony_ci	ah->ah_info = *ah_info;
206262306a36Sopenharmony_ci
206362306a36Sopenharmony_ci	if (type == IRDMA_PUDA_RSRC_TYPE_ILQ)
206462306a36Sopenharmony_ci		err = irdma_ah_cqp_op(rf, ah, IRDMA_OP_AH_CREATE, wait,
206562306a36Sopenharmony_ci				      irdma_ilq_ah_cb, cb_param);
206662306a36Sopenharmony_ci	else
206762306a36Sopenharmony_ci		err = irdma_ah_cqp_op(rf, ah, IRDMA_OP_AH_CREATE, wait,
206862306a36Sopenharmony_ci				      irdma_ieq_ah_cb, cb_param);
206962306a36Sopenharmony_ci
207062306a36Sopenharmony_ci	if (err)
207162306a36Sopenharmony_ci		goto error;
207262306a36Sopenharmony_ci	return 0;
207362306a36Sopenharmony_ci
207462306a36Sopenharmony_cierror:
207562306a36Sopenharmony_ci	irdma_free_rsrc(rf, rf->allocated_ahs, ah->ah_info.ah_idx);
207662306a36Sopenharmony_cierr_free:
207762306a36Sopenharmony_ci	kfree(ah);
207862306a36Sopenharmony_ci	*ah_ret = NULL;
207962306a36Sopenharmony_ci	return -ENOMEM;
208062306a36Sopenharmony_ci}
208162306a36Sopenharmony_ci
208262306a36Sopenharmony_ci/**
208362306a36Sopenharmony_ci * irdma_puda_free_ah - free a puda address handle
208462306a36Sopenharmony_ci * @dev: device pointer
208562306a36Sopenharmony_ci * @ah: The address handle to free
208662306a36Sopenharmony_ci */
208762306a36Sopenharmony_civoid irdma_puda_free_ah(struct irdma_sc_dev *dev, struct irdma_sc_ah *ah)
208862306a36Sopenharmony_ci{
208962306a36Sopenharmony_ci	struct irdma_pci_f *rf = dev_to_rf(dev);
209062306a36Sopenharmony_ci
209162306a36Sopenharmony_ci	if (!ah)
209262306a36Sopenharmony_ci		return;
209362306a36Sopenharmony_ci
209462306a36Sopenharmony_ci	if (ah->ah_info.ah_valid) {
209562306a36Sopenharmony_ci		irdma_ah_cqp_op(rf, ah, IRDMA_OP_AH_DESTROY, false, NULL, NULL);
209662306a36Sopenharmony_ci		irdma_free_rsrc(rf, rf->allocated_ahs, ah->ah_info.ah_idx);
209762306a36Sopenharmony_ci	}
209862306a36Sopenharmony_ci
209962306a36Sopenharmony_ci	kfree(ah);
210062306a36Sopenharmony_ci}
210162306a36Sopenharmony_ci
210262306a36Sopenharmony_ci/**
210362306a36Sopenharmony_ci * irdma_gsi_ud_qp_ah_cb - callback after creation of AH for GSI/ID QP
210462306a36Sopenharmony_ci * @cqp_request: pointer to cqp_request of create AH
210562306a36Sopenharmony_ci */
210662306a36Sopenharmony_civoid irdma_gsi_ud_qp_ah_cb(struct irdma_cqp_request *cqp_request)
210762306a36Sopenharmony_ci{
210862306a36Sopenharmony_ci	struct irdma_sc_ah *sc_ah = cqp_request->param;
210962306a36Sopenharmony_ci
211062306a36Sopenharmony_ci	if (!cqp_request->compl_info.op_ret_val)
211162306a36Sopenharmony_ci		sc_ah->ah_info.ah_valid = true;
211262306a36Sopenharmony_ci	else
211362306a36Sopenharmony_ci		sc_ah->ah_info.ah_valid = false;
211462306a36Sopenharmony_ci}
211562306a36Sopenharmony_ci
211662306a36Sopenharmony_ci/**
211762306a36Sopenharmony_ci * irdma_prm_add_pble_mem - add moemory to pble resources
211862306a36Sopenharmony_ci * @pprm: pble resource manager
211962306a36Sopenharmony_ci * @pchunk: chunk of memory to add
212062306a36Sopenharmony_ci */
212162306a36Sopenharmony_ciint irdma_prm_add_pble_mem(struct irdma_pble_prm *pprm,
212262306a36Sopenharmony_ci			   struct irdma_chunk *pchunk)
212362306a36Sopenharmony_ci{
212462306a36Sopenharmony_ci	u64 sizeofbitmap;
212562306a36Sopenharmony_ci
212662306a36Sopenharmony_ci	if (pchunk->size & 0xfff)
212762306a36Sopenharmony_ci		return -EINVAL;
212862306a36Sopenharmony_ci
212962306a36Sopenharmony_ci	sizeofbitmap = (u64)pchunk->size >> pprm->pble_shift;
213062306a36Sopenharmony_ci
213162306a36Sopenharmony_ci	pchunk->bitmapbuf = bitmap_zalloc(sizeofbitmap, GFP_KERNEL);
213262306a36Sopenharmony_ci	if (!pchunk->bitmapbuf)
213362306a36Sopenharmony_ci		return -ENOMEM;
213462306a36Sopenharmony_ci
213562306a36Sopenharmony_ci	pchunk->sizeofbitmap = sizeofbitmap;
213662306a36Sopenharmony_ci	/* each pble is 8 bytes hence shift by 3 */
213762306a36Sopenharmony_ci	pprm->total_pble_alloc += pchunk->size >> 3;
213862306a36Sopenharmony_ci	pprm->free_pble_cnt += pchunk->size >> 3;
213962306a36Sopenharmony_ci
214062306a36Sopenharmony_ci	return 0;
214162306a36Sopenharmony_ci}
214262306a36Sopenharmony_ci
214362306a36Sopenharmony_ci/**
214462306a36Sopenharmony_ci * irdma_prm_get_pbles - get pble's from prm
214562306a36Sopenharmony_ci * @pprm: pble resource manager
214662306a36Sopenharmony_ci * @chunkinfo: nformation about chunk where pble's were acquired
214762306a36Sopenharmony_ci * @mem_size: size of pble memory needed
214862306a36Sopenharmony_ci * @vaddr: returns virtual address of pble memory
214962306a36Sopenharmony_ci * @fpm_addr: returns fpm address of pble memory
215062306a36Sopenharmony_ci */
215162306a36Sopenharmony_ciint irdma_prm_get_pbles(struct irdma_pble_prm *pprm,
215262306a36Sopenharmony_ci			struct irdma_pble_chunkinfo *chunkinfo, u64 mem_size,
215362306a36Sopenharmony_ci			u64 **vaddr, u64 *fpm_addr)
215462306a36Sopenharmony_ci{
215562306a36Sopenharmony_ci	u64 bits_needed;
215662306a36Sopenharmony_ci	u64 bit_idx = PBLE_INVALID_IDX;
215762306a36Sopenharmony_ci	struct irdma_chunk *pchunk = NULL;
215862306a36Sopenharmony_ci	struct list_head *chunk_entry = pprm->clist.next;
215962306a36Sopenharmony_ci	u32 offset;
216062306a36Sopenharmony_ci	unsigned long flags;
216162306a36Sopenharmony_ci	*vaddr = NULL;
216262306a36Sopenharmony_ci	*fpm_addr = 0;
216362306a36Sopenharmony_ci
216462306a36Sopenharmony_ci	bits_needed = DIV_ROUND_UP_ULL(mem_size, BIT_ULL(pprm->pble_shift));
216562306a36Sopenharmony_ci
216662306a36Sopenharmony_ci	spin_lock_irqsave(&pprm->prm_lock, flags);
216762306a36Sopenharmony_ci	while (chunk_entry != &pprm->clist) {
216862306a36Sopenharmony_ci		pchunk = (struct irdma_chunk *)chunk_entry;
216962306a36Sopenharmony_ci		bit_idx = bitmap_find_next_zero_area(pchunk->bitmapbuf,
217062306a36Sopenharmony_ci						     pchunk->sizeofbitmap, 0,
217162306a36Sopenharmony_ci						     bits_needed, 0);
217262306a36Sopenharmony_ci		if (bit_idx < pchunk->sizeofbitmap)
217362306a36Sopenharmony_ci			break;
217462306a36Sopenharmony_ci
217562306a36Sopenharmony_ci		/* list.next used macro */
217662306a36Sopenharmony_ci		chunk_entry = pchunk->list.next;
217762306a36Sopenharmony_ci	}
217862306a36Sopenharmony_ci
217962306a36Sopenharmony_ci	if (!pchunk || bit_idx >= pchunk->sizeofbitmap) {
218062306a36Sopenharmony_ci		spin_unlock_irqrestore(&pprm->prm_lock, flags);
218162306a36Sopenharmony_ci		return -ENOMEM;
218262306a36Sopenharmony_ci	}
218362306a36Sopenharmony_ci
218462306a36Sopenharmony_ci	bitmap_set(pchunk->bitmapbuf, bit_idx, bits_needed);
218562306a36Sopenharmony_ci	offset = bit_idx << pprm->pble_shift;
218662306a36Sopenharmony_ci	*vaddr = pchunk->vaddr + offset;
218762306a36Sopenharmony_ci	*fpm_addr = pchunk->fpm_addr + offset;
218862306a36Sopenharmony_ci
218962306a36Sopenharmony_ci	chunkinfo->pchunk = pchunk;
219062306a36Sopenharmony_ci	chunkinfo->bit_idx = bit_idx;
219162306a36Sopenharmony_ci	chunkinfo->bits_used = bits_needed;
219262306a36Sopenharmony_ci	/* 3 is sizeof pble divide */
219362306a36Sopenharmony_ci	pprm->free_pble_cnt -= chunkinfo->bits_used << (pprm->pble_shift - 3);
219462306a36Sopenharmony_ci	spin_unlock_irqrestore(&pprm->prm_lock, flags);
219562306a36Sopenharmony_ci
219662306a36Sopenharmony_ci	return 0;
219762306a36Sopenharmony_ci}
219862306a36Sopenharmony_ci
219962306a36Sopenharmony_ci/**
220062306a36Sopenharmony_ci * irdma_prm_return_pbles - return pbles back to prm
220162306a36Sopenharmony_ci * @pprm: pble resource manager
220262306a36Sopenharmony_ci * @chunkinfo: chunk where pble's were acquired and to be freed
220362306a36Sopenharmony_ci */
220462306a36Sopenharmony_civoid irdma_prm_return_pbles(struct irdma_pble_prm *pprm,
220562306a36Sopenharmony_ci			    struct irdma_pble_chunkinfo *chunkinfo)
220662306a36Sopenharmony_ci{
220762306a36Sopenharmony_ci	unsigned long flags;
220862306a36Sopenharmony_ci
220962306a36Sopenharmony_ci	spin_lock_irqsave(&pprm->prm_lock, flags);
221062306a36Sopenharmony_ci	pprm->free_pble_cnt += chunkinfo->bits_used << (pprm->pble_shift - 3);
221162306a36Sopenharmony_ci	bitmap_clear(chunkinfo->pchunk->bitmapbuf, chunkinfo->bit_idx,
221262306a36Sopenharmony_ci		     chunkinfo->bits_used);
221362306a36Sopenharmony_ci	spin_unlock_irqrestore(&pprm->prm_lock, flags);
221462306a36Sopenharmony_ci}
221562306a36Sopenharmony_ci
221662306a36Sopenharmony_ciint irdma_map_vm_page_list(struct irdma_hw *hw, void *va, dma_addr_t *pg_dma,
221762306a36Sopenharmony_ci			   u32 pg_cnt)
221862306a36Sopenharmony_ci{
221962306a36Sopenharmony_ci	struct page *vm_page;
222062306a36Sopenharmony_ci	int i;
222162306a36Sopenharmony_ci	u8 *addr;
222262306a36Sopenharmony_ci
222362306a36Sopenharmony_ci	addr = (u8 *)(uintptr_t)va;
222462306a36Sopenharmony_ci	for (i = 0; i < pg_cnt; i++) {
222562306a36Sopenharmony_ci		vm_page = vmalloc_to_page(addr);
222662306a36Sopenharmony_ci		if (!vm_page)
222762306a36Sopenharmony_ci			goto err;
222862306a36Sopenharmony_ci
222962306a36Sopenharmony_ci		pg_dma[i] = dma_map_page(hw->device, vm_page, 0, PAGE_SIZE,
223062306a36Sopenharmony_ci					 DMA_BIDIRECTIONAL);
223162306a36Sopenharmony_ci		if (dma_mapping_error(hw->device, pg_dma[i]))
223262306a36Sopenharmony_ci			goto err;
223362306a36Sopenharmony_ci
223462306a36Sopenharmony_ci		addr += PAGE_SIZE;
223562306a36Sopenharmony_ci	}
223662306a36Sopenharmony_ci
223762306a36Sopenharmony_ci	return 0;
223862306a36Sopenharmony_ci
223962306a36Sopenharmony_cierr:
224062306a36Sopenharmony_ci	irdma_unmap_vm_page_list(hw, pg_dma, i);
224162306a36Sopenharmony_ci	return -ENOMEM;
224262306a36Sopenharmony_ci}
224362306a36Sopenharmony_ci
224462306a36Sopenharmony_civoid irdma_unmap_vm_page_list(struct irdma_hw *hw, dma_addr_t *pg_dma, u32 pg_cnt)
224562306a36Sopenharmony_ci{
224662306a36Sopenharmony_ci	int i;
224762306a36Sopenharmony_ci
224862306a36Sopenharmony_ci	for (i = 0; i < pg_cnt; i++)
224962306a36Sopenharmony_ci		dma_unmap_page(hw->device, pg_dma[i], PAGE_SIZE, DMA_BIDIRECTIONAL);
225062306a36Sopenharmony_ci}
225162306a36Sopenharmony_ci
225262306a36Sopenharmony_ci/**
225362306a36Sopenharmony_ci * irdma_pble_free_paged_mem - free virtual paged memory
225462306a36Sopenharmony_ci * @chunk: chunk to free with paged memory
225562306a36Sopenharmony_ci */
225662306a36Sopenharmony_civoid irdma_pble_free_paged_mem(struct irdma_chunk *chunk)
225762306a36Sopenharmony_ci{
225862306a36Sopenharmony_ci	if (!chunk->pg_cnt)
225962306a36Sopenharmony_ci		goto done;
226062306a36Sopenharmony_ci
226162306a36Sopenharmony_ci	irdma_unmap_vm_page_list(chunk->dev->hw, chunk->dmainfo.dmaaddrs,
226262306a36Sopenharmony_ci				 chunk->pg_cnt);
226362306a36Sopenharmony_ci
226462306a36Sopenharmony_cidone:
226562306a36Sopenharmony_ci	kfree(chunk->dmainfo.dmaaddrs);
226662306a36Sopenharmony_ci	chunk->dmainfo.dmaaddrs = NULL;
226762306a36Sopenharmony_ci	vfree(chunk->vaddr);
226862306a36Sopenharmony_ci	chunk->vaddr = NULL;
226962306a36Sopenharmony_ci	chunk->type = 0;
227062306a36Sopenharmony_ci}
227162306a36Sopenharmony_ci
227262306a36Sopenharmony_ci/**
227362306a36Sopenharmony_ci * irdma_pble_get_paged_mem -allocate paged memory for pbles
227462306a36Sopenharmony_ci * @chunk: chunk to add for paged memory
227562306a36Sopenharmony_ci * @pg_cnt: number of pages needed
227662306a36Sopenharmony_ci */
227762306a36Sopenharmony_ciint irdma_pble_get_paged_mem(struct irdma_chunk *chunk, u32 pg_cnt)
227862306a36Sopenharmony_ci{
227962306a36Sopenharmony_ci	u32 size;
228062306a36Sopenharmony_ci	void *va;
228162306a36Sopenharmony_ci
228262306a36Sopenharmony_ci	chunk->dmainfo.dmaaddrs = kzalloc(pg_cnt << 3, GFP_KERNEL);
228362306a36Sopenharmony_ci	if (!chunk->dmainfo.dmaaddrs)
228462306a36Sopenharmony_ci		return -ENOMEM;
228562306a36Sopenharmony_ci
228662306a36Sopenharmony_ci	size = PAGE_SIZE * pg_cnt;
228762306a36Sopenharmony_ci	va = vmalloc(size);
228862306a36Sopenharmony_ci	if (!va)
228962306a36Sopenharmony_ci		goto err;
229062306a36Sopenharmony_ci
229162306a36Sopenharmony_ci	if (irdma_map_vm_page_list(chunk->dev->hw, va, chunk->dmainfo.dmaaddrs,
229262306a36Sopenharmony_ci				   pg_cnt)) {
229362306a36Sopenharmony_ci		vfree(va);
229462306a36Sopenharmony_ci		goto err;
229562306a36Sopenharmony_ci	}
229662306a36Sopenharmony_ci	chunk->vaddr = va;
229762306a36Sopenharmony_ci	chunk->size = size;
229862306a36Sopenharmony_ci	chunk->pg_cnt = pg_cnt;
229962306a36Sopenharmony_ci	chunk->type = PBLE_SD_PAGED;
230062306a36Sopenharmony_ci
230162306a36Sopenharmony_ci	return 0;
230262306a36Sopenharmony_cierr:
230362306a36Sopenharmony_ci	kfree(chunk->dmainfo.dmaaddrs);
230462306a36Sopenharmony_ci	chunk->dmainfo.dmaaddrs = NULL;
230562306a36Sopenharmony_ci
230662306a36Sopenharmony_ci	return -ENOMEM;
230762306a36Sopenharmony_ci}
230862306a36Sopenharmony_ci
230962306a36Sopenharmony_ci/**
231062306a36Sopenharmony_ci * irdma_alloc_ws_node_id - Allocate a tx scheduler node ID
231162306a36Sopenharmony_ci * @dev: device pointer
231262306a36Sopenharmony_ci */
231362306a36Sopenharmony_ciu16 irdma_alloc_ws_node_id(struct irdma_sc_dev *dev)
231462306a36Sopenharmony_ci{
231562306a36Sopenharmony_ci	struct irdma_pci_f *rf = dev_to_rf(dev);
231662306a36Sopenharmony_ci	u32 next = 1;
231762306a36Sopenharmony_ci	u32 node_id;
231862306a36Sopenharmony_ci
231962306a36Sopenharmony_ci	if (irdma_alloc_rsrc(rf, rf->allocated_ws_nodes, rf->max_ws_node_id,
232062306a36Sopenharmony_ci			     &node_id, &next))
232162306a36Sopenharmony_ci		return IRDMA_WS_NODE_INVALID;
232262306a36Sopenharmony_ci
232362306a36Sopenharmony_ci	return (u16)node_id;
232462306a36Sopenharmony_ci}
232562306a36Sopenharmony_ci
232662306a36Sopenharmony_ci/**
232762306a36Sopenharmony_ci * irdma_free_ws_node_id - Free a tx scheduler node ID
232862306a36Sopenharmony_ci * @dev: device pointer
232962306a36Sopenharmony_ci * @node_id: Work scheduler node ID
233062306a36Sopenharmony_ci */
233162306a36Sopenharmony_civoid irdma_free_ws_node_id(struct irdma_sc_dev *dev, u16 node_id)
233262306a36Sopenharmony_ci{
233362306a36Sopenharmony_ci	struct irdma_pci_f *rf = dev_to_rf(dev);
233462306a36Sopenharmony_ci
233562306a36Sopenharmony_ci	irdma_free_rsrc(rf, rf->allocated_ws_nodes, (u32)node_id);
233662306a36Sopenharmony_ci}
233762306a36Sopenharmony_ci
233862306a36Sopenharmony_ci/**
233962306a36Sopenharmony_ci * irdma_modify_qp_to_err - Modify a QP to error
234062306a36Sopenharmony_ci * @sc_qp: qp structure
234162306a36Sopenharmony_ci */
234262306a36Sopenharmony_civoid irdma_modify_qp_to_err(struct irdma_sc_qp *sc_qp)
234362306a36Sopenharmony_ci{
234462306a36Sopenharmony_ci	struct irdma_qp *qp = sc_qp->qp_uk.back_qp;
234562306a36Sopenharmony_ci	struct ib_qp_attr attr;
234662306a36Sopenharmony_ci
234762306a36Sopenharmony_ci	if (qp->iwdev->rf->reset)
234862306a36Sopenharmony_ci		return;
234962306a36Sopenharmony_ci	attr.qp_state = IB_QPS_ERR;
235062306a36Sopenharmony_ci
235162306a36Sopenharmony_ci	if (rdma_protocol_roce(qp->ibqp.device, 1))
235262306a36Sopenharmony_ci		irdma_modify_qp_roce(&qp->ibqp, &attr, IB_QP_STATE, NULL);
235362306a36Sopenharmony_ci	else
235462306a36Sopenharmony_ci		irdma_modify_qp(&qp->ibqp, &attr, IB_QP_STATE, NULL);
235562306a36Sopenharmony_ci}
235662306a36Sopenharmony_ci
235762306a36Sopenharmony_civoid irdma_ib_qp_event(struct irdma_qp *iwqp, enum irdma_qp_event_type event)
235862306a36Sopenharmony_ci{
235962306a36Sopenharmony_ci	struct ib_event ibevent;
236062306a36Sopenharmony_ci
236162306a36Sopenharmony_ci	if (!iwqp->ibqp.event_handler)
236262306a36Sopenharmony_ci		return;
236362306a36Sopenharmony_ci
236462306a36Sopenharmony_ci	switch (event) {
236562306a36Sopenharmony_ci	case IRDMA_QP_EVENT_CATASTROPHIC:
236662306a36Sopenharmony_ci		ibevent.event = IB_EVENT_QP_FATAL;
236762306a36Sopenharmony_ci		break;
236862306a36Sopenharmony_ci	case IRDMA_QP_EVENT_ACCESS_ERR:
236962306a36Sopenharmony_ci		ibevent.event = IB_EVENT_QP_ACCESS_ERR;
237062306a36Sopenharmony_ci		break;
237162306a36Sopenharmony_ci	case IRDMA_QP_EVENT_REQ_ERR:
237262306a36Sopenharmony_ci		ibevent.event = IB_EVENT_QP_REQ_ERR;
237362306a36Sopenharmony_ci		break;
237462306a36Sopenharmony_ci	}
237562306a36Sopenharmony_ci	ibevent.device = iwqp->ibqp.device;
237662306a36Sopenharmony_ci	ibevent.element.qp = &iwqp->ibqp;
237762306a36Sopenharmony_ci	iwqp->ibqp.event_handler(&ibevent, iwqp->ibqp.qp_context);
237862306a36Sopenharmony_ci}
237962306a36Sopenharmony_ci
238062306a36Sopenharmony_cibool irdma_cq_empty(struct irdma_cq *iwcq)
238162306a36Sopenharmony_ci{
238262306a36Sopenharmony_ci	struct irdma_cq_uk *ukcq;
238362306a36Sopenharmony_ci	u64 qword3;
238462306a36Sopenharmony_ci	__le64 *cqe;
238562306a36Sopenharmony_ci	u8 polarity;
238662306a36Sopenharmony_ci
238762306a36Sopenharmony_ci	ukcq  = &iwcq->sc_cq.cq_uk;
238862306a36Sopenharmony_ci	cqe = IRDMA_GET_CURRENT_CQ_ELEM(ukcq);
238962306a36Sopenharmony_ci	get_64bit_val(cqe, 24, &qword3);
239062306a36Sopenharmony_ci	polarity = (u8)FIELD_GET(IRDMA_CQ_VALID, qword3);
239162306a36Sopenharmony_ci
239262306a36Sopenharmony_ci	return polarity != ukcq->polarity;
239362306a36Sopenharmony_ci}
239462306a36Sopenharmony_ci
239562306a36Sopenharmony_civoid irdma_remove_cmpls_list(struct irdma_cq *iwcq)
239662306a36Sopenharmony_ci{
239762306a36Sopenharmony_ci	struct irdma_cmpl_gen *cmpl_node;
239862306a36Sopenharmony_ci	struct list_head *tmp_node, *list_node;
239962306a36Sopenharmony_ci
240062306a36Sopenharmony_ci	list_for_each_safe (list_node, tmp_node, &iwcq->cmpl_generated) {
240162306a36Sopenharmony_ci		cmpl_node = list_entry(list_node, struct irdma_cmpl_gen, list);
240262306a36Sopenharmony_ci		list_del(&cmpl_node->list);
240362306a36Sopenharmony_ci		kfree(cmpl_node);
240462306a36Sopenharmony_ci	}
240562306a36Sopenharmony_ci}
240662306a36Sopenharmony_ci
240762306a36Sopenharmony_ciint irdma_generated_cmpls(struct irdma_cq *iwcq, struct irdma_cq_poll_info *cq_poll_info)
240862306a36Sopenharmony_ci{
240962306a36Sopenharmony_ci	struct irdma_cmpl_gen *cmpl;
241062306a36Sopenharmony_ci
241162306a36Sopenharmony_ci	if (list_empty(&iwcq->cmpl_generated))
241262306a36Sopenharmony_ci		return -ENOENT;
241362306a36Sopenharmony_ci	cmpl = list_first_entry_or_null(&iwcq->cmpl_generated, struct irdma_cmpl_gen, list);
241462306a36Sopenharmony_ci	list_del(&cmpl->list);
241562306a36Sopenharmony_ci	memcpy(cq_poll_info, &cmpl->cpi, sizeof(*cq_poll_info));
241662306a36Sopenharmony_ci	kfree(cmpl);
241762306a36Sopenharmony_ci
241862306a36Sopenharmony_ci	ibdev_dbg(iwcq->ibcq.device,
241962306a36Sopenharmony_ci		  "VERBS: %s: Poll artificially generated completion for QP 0x%X, op %u, wr_id=0x%llx\n",
242062306a36Sopenharmony_ci		  __func__, cq_poll_info->qp_id, cq_poll_info->op_type,
242162306a36Sopenharmony_ci		  cq_poll_info->wr_id);
242262306a36Sopenharmony_ci
242362306a36Sopenharmony_ci	return 0;
242462306a36Sopenharmony_ci}
242562306a36Sopenharmony_ci
242662306a36Sopenharmony_ci/**
242762306a36Sopenharmony_ci * irdma_set_cpi_common_values - fill in values for polling info struct
242862306a36Sopenharmony_ci * @cpi: resulting structure of cq_poll_info type
242962306a36Sopenharmony_ci * @qp: QPair
243062306a36Sopenharmony_ci * @qp_num: id of the QP
243162306a36Sopenharmony_ci */
243262306a36Sopenharmony_cistatic void irdma_set_cpi_common_values(struct irdma_cq_poll_info *cpi,
243362306a36Sopenharmony_ci					struct irdma_qp_uk *qp, u32 qp_num)
243462306a36Sopenharmony_ci{
243562306a36Sopenharmony_ci	cpi->comp_status = IRDMA_COMPL_STATUS_FLUSHED;
243662306a36Sopenharmony_ci	cpi->error = true;
243762306a36Sopenharmony_ci	cpi->major_err = IRDMA_FLUSH_MAJOR_ERR;
243862306a36Sopenharmony_ci	cpi->minor_err = FLUSH_GENERAL_ERR;
243962306a36Sopenharmony_ci	cpi->qp_handle = (irdma_qp_handle)(uintptr_t)qp;
244062306a36Sopenharmony_ci	cpi->qp_id = qp_num;
244162306a36Sopenharmony_ci}
244262306a36Sopenharmony_ci
244362306a36Sopenharmony_cistatic inline void irdma_comp_handler(struct irdma_cq *cq)
244462306a36Sopenharmony_ci{
244562306a36Sopenharmony_ci	if (!cq->ibcq.comp_handler)
244662306a36Sopenharmony_ci		return;
244762306a36Sopenharmony_ci	if (atomic_cmpxchg(&cq->armed, 1, 0))
244862306a36Sopenharmony_ci		cq->ibcq.comp_handler(&cq->ibcq, cq->ibcq.cq_context);
244962306a36Sopenharmony_ci}
245062306a36Sopenharmony_ci
245162306a36Sopenharmony_civoid irdma_generate_flush_completions(struct irdma_qp *iwqp)
245262306a36Sopenharmony_ci{
245362306a36Sopenharmony_ci	struct irdma_qp_uk *qp = &iwqp->sc_qp.qp_uk;
245462306a36Sopenharmony_ci	struct irdma_ring *sq_ring = &qp->sq_ring;
245562306a36Sopenharmony_ci	struct irdma_ring *rq_ring = &qp->rq_ring;
245662306a36Sopenharmony_ci	struct irdma_cmpl_gen *cmpl;
245762306a36Sopenharmony_ci	__le64 *sw_wqe;
245862306a36Sopenharmony_ci	u64 wqe_qword;
245962306a36Sopenharmony_ci	u32 wqe_idx;
246062306a36Sopenharmony_ci	bool compl_generated = false;
246162306a36Sopenharmony_ci	unsigned long flags1;
246262306a36Sopenharmony_ci
246362306a36Sopenharmony_ci	spin_lock_irqsave(&iwqp->iwscq->lock, flags1);
246462306a36Sopenharmony_ci	if (irdma_cq_empty(iwqp->iwscq)) {
246562306a36Sopenharmony_ci		unsigned long flags2;
246662306a36Sopenharmony_ci
246762306a36Sopenharmony_ci		spin_lock_irqsave(&iwqp->lock, flags2);
246862306a36Sopenharmony_ci		while (IRDMA_RING_MORE_WORK(*sq_ring)) {
246962306a36Sopenharmony_ci			cmpl = kzalloc(sizeof(*cmpl), GFP_ATOMIC);
247062306a36Sopenharmony_ci			if (!cmpl) {
247162306a36Sopenharmony_ci				spin_unlock_irqrestore(&iwqp->lock, flags2);
247262306a36Sopenharmony_ci				spin_unlock_irqrestore(&iwqp->iwscq->lock, flags1);
247362306a36Sopenharmony_ci				return;
247462306a36Sopenharmony_ci			}
247562306a36Sopenharmony_ci
247662306a36Sopenharmony_ci			wqe_idx = sq_ring->tail;
247762306a36Sopenharmony_ci			irdma_set_cpi_common_values(&cmpl->cpi, qp, qp->qp_id);
247862306a36Sopenharmony_ci
247962306a36Sopenharmony_ci			cmpl->cpi.wr_id = qp->sq_wrtrk_array[wqe_idx].wrid;
248062306a36Sopenharmony_ci			sw_wqe = qp->sq_base[wqe_idx].elem;
248162306a36Sopenharmony_ci			get_64bit_val(sw_wqe, 24, &wqe_qword);
248262306a36Sopenharmony_ci			cmpl->cpi.op_type = (u8)FIELD_GET(IRDMAQPSQ_OPCODE, IRDMAQPSQ_OPCODE);
248362306a36Sopenharmony_ci			cmpl->cpi.q_type = IRDMA_CQE_QTYPE_SQ;
248462306a36Sopenharmony_ci			/* remove the SQ WR by moving SQ tail*/
248562306a36Sopenharmony_ci			IRDMA_RING_SET_TAIL(*sq_ring,
248662306a36Sopenharmony_ci				sq_ring->tail + qp->sq_wrtrk_array[sq_ring->tail].quanta);
248762306a36Sopenharmony_ci			if (cmpl->cpi.op_type == IRDMAQP_OP_NOP) {
248862306a36Sopenharmony_ci				kfree(cmpl);
248962306a36Sopenharmony_ci				continue;
249062306a36Sopenharmony_ci			}
249162306a36Sopenharmony_ci			ibdev_dbg(iwqp->iwscq->ibcq.device,
249262306a36Sopenharmony_ci				  "DEV: %s: adding wr_id = 0x%llx SQ Completion to list qp_id=%d\n",
249362306a36Sopenharmony_ci				  __func__, cmpl->cpi.wr_id, qp->qp_id);
249462306a36Sopenharmony_ci			list_add_tail(&cmpl->list, &iwqp->iwscq->cmpl_generated);
249562306a36Sopenharmony_ci			compl_generated = true;
249662306a36Sopenharmony_ci		}
249762306a36Sopenharmony_ci		spin_unlock_irqrestore(&iwqp->lock, flags2);
249862306a36Sopenharmony_ci		spin_unlock_irqrestore(&iwqp->iwscq->lock, flags1);
249962306a36Sopenharmony_ci		if (compl_generated)
250062306a36Sopenharmony_ci			irdma_comp_handler(iwqp->iwscq);
250162306a36Sopenharmony_ci	} else {
250262306a36Sopenharmony_ci		spin_unlock_irqrestore(&iwqp->iwscq->lock, flags1);
250362306a36Sopenharmony_ci		mod_delayed_work(iwqp->iwdev->cleanup_wq, &iwqp->dwork_flush,
250462306a36Sopenharmony_ci				 msecs_to_jiffies(IRDMA_FLUSH_DELAY_MS));
250562306a36Sopenharmony_ci	}
250662306a36Sopenharmony_ci
250762306a36Sopenharmony_ci	spin_lock_irqsave(&iwqp->iwrcq->lock, flags1);
250862306a36Sopenharmony_ci	if (irdma_cq_empty(iwqp->iwrcq)) {
250962306a36Sopenharmony_ci		unsigned long flags2;
251062306a36Sopenharmony_ci
251162306a36Sopenharmony_ci		spin_lock_irqsave(&iwqp->lock, flags2);
251262306a36Sopenharmony_ci		while (IRDMA_RING_MORE_WORK(*rq_ring)) {
251362306a36Sopenharmony_ci			cmpl = kzalloc(sizeof(*cmpl), GFP_ATOMIC);
251462306a36Sopenharmony_ci			if (!cmpl) {
251562306a36Sopenharmony_ci				spin_unlock_irqrestore(&iwqp->lock, flags2);
251662306a36Sopenharmony_ci				spin_unlock_irqrestore(&iwqp->iwrcq->lock, flags1);
251762306a36Sopenharmony_ci				return;
251862306a36Sopenharmony_ci			}
251962306a36Sopenharmony_ci
252062306a36Sopenharmony_ci			wqe_idx = rq_ring->tail;
252162306a36Sopenharmony_ci			irdma_set_cpi_common_values(&cmpl->cpi, qp, qp->qp_id);
252262306a36Sopenharmony_ci
252362306a36Sopenharmony_ci			cmpl->cpi.wr_id = qp->rq_wrid_array[wqe_idx];
252462306a36Sopenharmony_ci			cmpl->cpi.op_type = IRDMA_OP_TYPE_REC;
252562306a36Sopenharmony_ci			cmpl->cpi.q_type = IRDMA_CQE_QTYPE_RQ;
252662306a36Sopenharmony_ci			/* remove the RQ WR by moving RQ tail */
252762306a36Sopenharmony_ci			IRDMA_RING_SET_TAIL(*rq_ring, rq_ring->tail + 1);
252862306a36Sopenharmony_ci			ibdev_dbg(iwqp->iwrcq->ibcq.device,
252962306a36Sopenharmony_ci				  "DEV: %s: adding wr_id = 0x%llx RQ Completion to list qp_id=%d, wqe_idx=%d\n",
253062306a36Sopenharmony_ci				  __func__, cmpl->cpi.wr_id, qp->qp_id,
253162306a36Sopenharmony_ci				  wqe_idx);
253262306a36Sopenharmony_ci			list_add_tail(&cmpl->list, &iwqp->iwrcq->cmpl_generated);
253362306a36Sopenharmony_ci
253462306a36Sopenharmony_ci			compl_generated = true;
253562306a36Sopenharmony_ci		}
253662306a36Sopenharmony_ci		spin_unlock_irqrestore(&iwqp->lock, flags2);
253762306a36Sopenharmony_ci		spin_unlock_irqrestore(&iwqp->iwrcq->lock, flags1);
253862306a36Sopenharmony_ci		if (compl_generated)
253962306a36Sopenharmony_ci			irdma_comp_handler(iwqp->iwrcq);
254062306a36Sopenharmony_ci	} else {
254162306a36Sopenharmony_ci		spin_unlock_irqrestore(&iwqp->iwrcq->lock, flags1);
254262306a36Sopenharmony_ci		mod_delayed_work(iwqp->iwdev->cleanup_wq, &iwqp->dwork_flush,
254362306a36Sopenharmony_ci				 msecs_to_jiffies(IRDMA_FLUSH_DELAY_MS));
254462306a36Sopenharmony_ci	}
254562306a36Sopenharmony_ci}
2546