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