18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 28c2ecf20Sopenharmony_ci/* Copyright (c) 2015-2018 Mellanox Technologies. All rights reserved */ 38c2ecf20Sopenharmony_ci 48c2ecf20Sopenharmony_ci#include <linux/kernel.h> 58c2ecf20Sopenharmony_ci#include <linux/module.h> 68c2ecf20Sopenharmony_ci#include <linux/export.h> 78c2ecf20Sopenharmony_ci#include <linux/err.h> 88c2ecf20Sopenharmony_ci#include <linux/device.h> 98c2ecf20Sopenharmony_ci#include <linux/pci.h> 108c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 118c2ecf20Sopenharmony_ci#include <linux/wait.h> 128c2ecf20Sopenharmony_ci#include <linux/types.h> 138c2ecf20Sopenharmony_ci#include <linux/skbuff.h> 148c2ecf20Sopenharmony_ci#include <linux/if_vlan.h> 158c2ecf20Sopenharmony_ci#include <linux/log2.h> 168c2ecf20Sopenharmony_ci#include <linux/string.h> 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_ci#include "pci_hw.h" 198c2ecf20Sopenharmony_ci#include "pci.h" 208c2ecf20Sopenharmony_ci#include "core.h" 218c2ecf20Sopenharmony_ci#include "cmd.h" 228c2ecf20Sopenharmony_ci#include "port.h" 238c2ecf20Sopenharmony_ci#include "resources.h" 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ci#define mlxsw_pci_write32(mlxsw_pci, reg, val) \ 268c2ecf20Sopenharmony_ci iowrite32be(val, (mlxsw_pci)->hw_addr + (MLXSW_PCI_ ## reg)) 278c2ecf20Sopenharmony_ci#define mlxsw_pci_read32(mlxsw_pci, reg) \ 288c2ecf20Sopenharmony_ci ioread32be((mlxsw_pci)->hw_addr + (MLXSW_PCI_ ## reg)) 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_cienum mlxsw_pci_queue_type { 318c2ecf20Sopenharmony_ci MLXSW_PCI_QUEUE_TYPE_SDQ, 328c2ecf20Sopenharmony_ci MLXSW_PCI_QUEUE_TYPE_RDQ, 338c2ecf20Sopenharmony_ci MLXSW_PCI_QUEUE_TYPE_CQ, 348c2ecf20Sopenharmony_ci MLXSW_PCI_QUEUE_TYPE_EQ, 358c2ecf20Sopenharmony_ci}; 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_ci#define MLXSW_PCI_QUEUE_TYPE_COUNT 4 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_cistatic const u16 mlxsw_pci_doorbell_type_offset[] = { 408c2ecf20Sopenharmony_ci MLXSW_PCI_DOORBELL_SDQ_OFFSET, /* for type MLXSW_PCI_QUEUE_TYPE_SDQ */ 418c2ecf20Sopenharmony_ci MLXSW_PCI_DOORBELL_RDQ_OFFSET, /* for type MLXSW_PCI_QUEUE_TYPE_RDQ */ 428c2ecf20Sopenharmony_ci MLXSW_PCI_DOORBELL_CQ_OFFSET, /* for type MLXSW_PCI_QUEUE_TYPE_CQ */ 438c2ecf20Sopenharmony_ci MLXSW_PCI_DOORBELL_EQ_OFFSET, /* for type MLXSW_PCI_QUEUE_TYPE_EQ */ 448c2ecf20Sopenharmony_ci}; 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_cistatic const u16 mlxsw_pci_doorbell_arm_type_offset[] = { 478c2ecf20Sopenharmony_ci 0, /* unused */ 488c2ecf20Sopenharmony_ci 0, /* unused */ 498c2ecf20Sopenharmony_ci MLXSW_PCI_DOORBELL_ARM_CQ_OFFSET, /* for type MLXSW_PCI_QUEUE_TYPE_CQ */ 508c2ecf20Sopenharmony_ci MLXSW_PCI_DOORBELL_ARM_EQ_OFFSET, /* for type MLXSW_PCI_QUEUE_TYPE_EQ */ 518c2ecf20Sopenharmony_ci}; 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_cistruct mlxsw_pci_mem_item { 548c2ecf20Sopenharmony_ci char *buf; 558c2ecf20Sopenharmony_ci dma_addr_t mapaddr; 568c2ecf20Sopenharmony_ci size_t size; 578c2ecf20Sopenharmony_ci}; 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_cistruct mlxsw_pci_queue_elem_info { 608c2ecf20Sopenharmony_ci char *elem; /* pointer to actual dma mapped element mem chunk */ 618c2ecf20Sopenharmony_ci union { 628c2ecf20Sopenharmony_ci struct { 638c2ecf20Sopenharmony_ci struct sk_buff *skb; 648c2ecf20Sopenharmony_ci } sdq; 658c2ecf20Sopenharmony_ci struct { 668c2ecf20Sopenharmony_ci struct sk_buff *skb; 678c2ecf20Sopenharmony_ci } rdq; 688c2ecf20Sopenharmony_ci } u; 698c2ecf20Sopenharmony_ci}; 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_cistruct mlxsw_pci_queue { 728c2ecf20Sopenharmony_ci spinlock_t lock; /* for queue accesses */ 738c2ecf20Sopenharmony_ci struct mlxsw_pci_mem_item mem_item; 748c2ecf20Sopenharmony_ci struct mlxsw_pci_queue_elem_info *elem_info; 758c2ecf20Sopenharmony_ci u16 producer_counter; 768c2ecf20Sopenharmony_ci u16 consumer_counter; 778c2ecf20Sopenharmony_ci u16 count; /* number of elements in queue */ 788c2ecf20Sopenharmony_ci u8 num; /* queue number */ 798c2ecf20Sopenharmony_ci u8 elem_size; /* size of one element */ 808c2ecf20Sopenharmony_ci enum mlxsw_pci_queue_type type; 818c2ecf20Sopenharmony_ci struct tasklet_struct tasklet; /* queue processing tasklet */ 828c2ecf20Sopenharmony_ci struct mlxsw_pci *pci; 838c2ecf20Sopenharmony_ci union { 848c2ecf20Sopenharmony_ci struct { 858c2ecf20Sopenharmony_ci u32 comp_sdq_count; 868c2ecf20Sopenharmony_ci u32 comp_rdq_count; 878c2ecf20Sopenharmony_ci enum mlxsw_pci_cqe_v v; 888c2ecf20Sopenharmony_ci } cq; 898c2ecf20Sopenharmony_ci struct { 908c2ecf20Sopenharmony_ci u32 ev_cmd_count; 918c2ecf20Sopenharmony_ci u32 ev_comp_count; 928c2ecf20Sopenharmony_ci u32 ev_other_count; 938c2ecf20Sopenharmony_ci } eq; 948c2ecf20Sopenharmony_ci } u; 958c2ecf20Sopenharmony_ci}; 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_cistruct mlxsw_pci_queue_type_group { 988c2ecf20Sopenharmony_ci struct mlxsw_pci_queue *q; 998c2ecf20Sopenharmony_ci u8 count; /* number of queues in group */ 1008c2ecf20Sopenharmony_ci}; 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_cistruct mlxsw_pci { 1038c2ecf20Sopenharmony_ci struct pci_dev *pdev; 1048c2ecf20Sopenharmony_ci u8 __iomem *hw_addr; 1058c2ecf20Sopenharmony_ci u64 free_running_clock_offset; 1068c2ecf20Sopenharmony_ci struct mlxsw_pci_queue_type_group queues[MLXSW_PCI_QUEUE_TYPE_COUNT]; 1078c2ecf20Sopenharmony_ci u32 doorbell_offset; 1088c2ecf20Sopenharmony_ci struct mlxsw_core *core; 1098c2ecf20Sopenharmony_ci struct { 1108c2ecf20Sopenharmony_ci struct mlxsw_pci_mem_item *items; 1118c2ecf20Sopenharmony_ci unsigned int count; 1128c2ecf20Sopenharmony_ci } fw_area; 1138c2ecf20Sopenharmony_ci struct { 1148c2ecf20Sopenharmony_ci struct mlxsw_pci_mem_item out_mbox; 1158c2ecf20Sopenharmony_ci struct mlxsw_pci_mem_item in_mbox; 1168c2ecf20Sopenharmony_ci struct mutex lock; /* Lock access to command registers */ 1178c2ecf20Sopenharmony_ci bool nopoll; 1188c2ecf20Sopenharmony_ci wait_queue_head_t wait; 1198c2ecf20Sopenharmony_ci bool wait_done; 1208c2ecf20Sopenharmony_ci struct { 1218c2ecf20Sopenharmony_ci u8 status; 1228c2ecf20Sopenharmony_ci u64 out_param; 1238c2ecf20Sopenharmony_ci } comp; 1248c2ecf20Sopenharmony_ci } cmd; 1258c2ecf20Sopenharmony_ci struct mlxsw_bus_info bus_info; 1268c2ecf20Sopenharmony_ci const struct pci_device_id *id; 1278c2ecf20Sopenharmony_ci enum mlxsw_pci_cqe_v max_cqe_ver; /* Maximal supported CQE version */ 1288c2ecf20Sopenharmony_ci u8 num_sdq_cqs; /* Number of CQs used for SDQs */ 1298c2ecf20Sopenharmony_ci}; 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_cistatic void mlxsw_pci_queue_tasklet_schedule(struct mlxsw_pci_queue *q) 1328c2ecf20Sopenharmony_ci{ 1338c2ecf20Sopenharmony_ci tasklet_schedule(&q->tasklet); 1348c2ecf20Sopenharmony_ci} 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_cistatic char *__mlxsw_pci_queue_elem_get(struct mlxsw_pci_queue *q, 1378c2ecf20Sopenharmony_ci size_t elem_size, int elem_index) 1388c2ecf20Sopenharmony_ci{ 1398c2ecf20Sopenharmony_ci return q->mem_item.buf + (elem_size * elem_index); 1408c2ecf20Sopenharmony_ci} 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_cistatic struct mlxsw_pci_queue_elem_info * 1438c2ecf20Sopenharmony_cimlxsw_pci_queue_elem_info_get(struct mlxsw_pci_queue *q, int elem_index) 1448c2ecf20Sopenharmony_ci{ 1458c2ecf20Sopenharmony_ci return &q->elem_info[elem_index]; 1468c2ecf20Sopenharmony_ci} 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_cistatic struct mlxsw_pci_queue_elem_info * 1498c2ecf20Sopenharmony_cimlxsw_pci_queue_elem_info_producer_get(struct mlxsw_pci_queue *q) 1508c2ecf20Sopenharmony_ci{ 1518c2ecf20Sopenharmony_ci int index = q->producer_counter & (q->count - 1); 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_ci if ((u16) (q->producer_counter - q->consumer_counter) == q->count) 1548c2ecf20Sopenharmony_ci return NULL; 1558c2ecf20Sopenharmony_ci return mlxsw_pci_queue_elem_info_get(q, index); 1568c2ecf20Sopenharmony_ci} 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_cistatic struct mlxsw_pci_queue_elem_info * 1598c2ecf20Sopenharmony_cimlxsw_pci_queue_elem_info_consumer_get(struct mlxsw_pci_queue *q) 1608c2ecf20Sopenharmony_ci{ 1618c2ecf20Sopenharmony_ci int index = q->consumer_counter & (q->count - 1); 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_ci return mlxsw_pci_queue_elem_info_get(q, index); 1648c2ecf20Sopenharmony_ci} 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_cistatic char *mlxsw_pci_queue_elem_get(struct mlxsw_pci_queue *q, int elem_index) 1678c2ecf20Sopenharmony_ci{ 1688c2ecf20Sopenharmony_ci return mlxsw_pci_queue_elem_info_get(q, elem_index)->elem; 1698c2ecf20Sopenharmony_ci} 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_cistatic bool mlxsw_pci_elem_hw_owned(struct mlxsw_pci_queue *q, bool owner_bit) 1728c2ecf20Sopenharmony_ci{ 1738c2ecf20Sopenharmony_ci return owner_bit != !!(q->consumer_counter & q->count); 1748c2ecf20Sopenharmony_ci} 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_cistatic struct mlxsw_pci_queue_type_group * 1778c2ecf20Sopenharmony_cimlxsw_pci_queue_type_group_get(struct mlxsw_pci *mlxsw_pci, 1788c2ecf20Sopenharmony_ci enum mlxsw_pci_queue_type q_type) 1798c2ecf20Sopenharmony_ci{ 1808c2ecf20Sopenharmony_ci return &mlxsw_pci->queues[q_type]; 1818c2ecf20Sopenharmony_ci} 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_cistatic u8 __mlxsw_pci_queue_count(struct mlxsw_pci *mlxsw_pci, 1848c2ecf20Sopenharmony_ci enum mlxsw_pci_queue_type q_type) 1858c2ecf20Sopenharmony_ci{ 1868c2ecf20Sopenharmony_ci struct mlxsw_pci_queue_type_group *queue_group; 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_ci queue_group = mlxsw_pci_queue_type_group_get(mlxsw_pci, q_type); 1898c2ecf20Sopenharmony_ci return queue_group->count; 1908c2ecf20Sopenharmony_ci} 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_cistatic u8 mlxsw_pci_sdq_count(struct mlxsw_pci *mlxsw_pci) 1938c2ecf20Sopenharmony_ci{ 1948c2ecf20Sopenharmony_ci return __mlxsw_pci_queue_count(mlxsw_pci, MLXSW_PCI_QUEUE_TYPE_SDQ); 1958c2ecf20Sopenharmony_ci} 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_cistatic u8 mlxsw_pci_cq_count(struct mlxsw_pci *mlxsw_pci) 1988c2ecf20Sopenharmony_ci{ 1998c2ecf20Sopenharmony_ci return __mlxsw_pci_queue_count(mlxsw_pci, MLXSW_PCI_QUEUE_TYPE_CQ); 2008c2ecf20Sopenharmony_ci} 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_cistatic struct mlxsw_pci_queue * 2038c2ecf20Sopenharmony_ci__mlxsw_pci_queue_get(struct mlxsw_pci *mlxsw_pci, 2048c2ecf20Sopenharmony_ci enum mlxsw_pci_queue_type q_type, u8 q_num) 2058c2ecf20Sopenharmony_ci{ 2068c2ecf20Sopenharmony_ci return &mlxsw_pci->queues[q_type].q[q_num]; 2078c2ecf20Sopenharmony_ci} 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_cistatic struct mlxsw_pci_queue *mlxsw_pci_sdq_get(struct mlxsw_pci *mlxsw_pci, 2108c2ecf20Sopenharmony_ci u8 q_num) 2118c2ecf20Sopenharmony_ci{ 2128c2ecf20Sopenharmony_ci return __mlxsw_pci_queue_get(mlxsw_pci, 2138c2ecf20Sopenharmony_ci MLXSW_PCI_QUEUE_TYPE_SDQ, q_num); 2148c2ecf20Sopenharmony_ci} 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_cistatic struct mlxsw_pci_queue *mlxsw_pci_rdq_get(struct mlxsw_pci *mlxsw_pci, 2178c2ecf20Sopenharmony_ci u8 q_num) 2188c2ecf20Sopenharmony_ci{ 2198c2ecf20Sopenharmony_ci return __mlxsw_pci_queue_get(mlxsw_pci, 2208c2ecf20Sopenharmony_ci MLXSW_PCI_QUEUE_TYPE_RDQ, q_num); 2218c2ecf20Sopenharmony_ci} 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_cistatic struct mlxsw_pci_queue *mlxsw_pci_cq_get(struct mlxsw_pci *mlxsw_pci, 2248c2ecf20Sopenharmony_ci u8 q_num) 2258c2ecf20Sopenharmony_ci{ 2268c2ecf20Sopenharmony_ci return __mlxsw_pci_queue_get(mlxsw_pci, MLXSW_PCI_QUEUE_TYPE_CQ, q_num); 2278c2ecf20Sopenharmony_ci} 2288c2ecf20Sopenharmony_ci 2298c2ecf20Sopenharmony_cistatic struct mlxsw_pci_queue *mlxsw_pci_eq_get(struct mlxsw_pci *mlxsw_pci, 2308c2ecf20Sopenharmony_ci u8 q_num) 2318c2ecf20Sopenharmony_ci{ 2328c2ecf20Sopenharmony_ci return __mlxsw_pci_queue_get(mlxsw_pci, MLXSW_PCI_QUEUE_TYPE_EQ, q_num); 2338c2ecf20Sopenharmony_ci} 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_cistatic void __mlxsw_pci_queue_doorbell_set(struct mlxsw_pci *mlxsw_pci, 2368c2ecf20Sopenharmony_ci struct mlxsw_pci_queue *q, 2378c2ecf20Sopenharmony_ci u16 val) 2388c2ecf20Sopenharmony_ci{ 2398c2ecf20Sopenharmony_ci mlxsw_pci_write32(mlxsw_pci, 2408c2ecf20Sopenharmony_ci DOORBELL(mlxsw_pci->doorbell_offset, 2418c2ecf20Sopenharmony_ci mlxsw_pci_doorbell_type_offset[q->type], 2428c2ecf20Sopenharmony_ci q->num), val); 2438c2ecf20Sopenharmony_ci} 2448c2ecf20Sopenharmony_ci 2458c2ecf20Sopenharmony_cistatic void __mlxsw_pci_queue_doorbell_arm_set(struct mlxsw_pci *mlxsw_pci, 2468c2ecf20Sopenharmony_ci struct mlxsw_pci_queue *q, 2478c2ecf20Sopenharmony_ci u16 val) 2488c2ecf20Sopenharmony_ci{ 2498c2ecf20Sopenharmony_ci mlxsw_pci_write32(mlxsw_pci, 2508c2ecf20Sopenharmony_ci DOORBELL(mlxsw_pci->doorbell_offset, 2518c2ecf20Sopenharmony_ci mlxsw_pci_doorbell_arm_type_offset[q->type], 2528c2ecf20Sopenharmony_ci q->num), val); 2538c2ecf20Sopenharmony_ci} 2548c2ecf20Sopenharmony_ci 2558c2ecf20Sopenharmony_cistatic void mlxsw_pci_queue_doorbell_producer_ring(struct mlxsw_pci *mlxsw_pci, 2568c2ecf20Sopenharmony_ci struct mlxsw_pci_queue *q) 2578c2ecf20Sopenharmony_ci{ 2588c2ecf20Sopenharmony_ci wmb(); /* ensure all writes are done before we ring a bell */ 2598c2ecf20Sopenharmony_ci __mlxsw_pci_queue_doorbell_set(mlxsw_pci, q, q->producer_counter); 2608c2ecf20Sopenharmony_ci} 2618c2ecf20Sopenharmony_ci 2628c2ecf20Sopenharmony_cistatic void mlxsw_pci_queue_doorbell_consumer_ring(struct mlxsw_pci *mlxsw_pci, 2638c2ecf20Sopenharmony_ci struct mlxsw_pci_queue *q) 2648c2ecf20Sopenharmony_ci{ 2658c2ecf20Sopenharmony_ci wmb(); /* ensure all writes are done before we ring a bell */ 2668c2ecf20Sopenharmony_ci __mlxsw_pci_queue_doorbell_set(mlxsw_pci, q, 2678c2ecf20Sopenharmony_ci q->consumer_counter + q->count); 2688c2ecf20Sopenharmony_ci} 2698c2ecf20Sopenharmony_ci 2708c2ecf20Sopenharmony_cistatic void 2718c2ecf20Sopenharmony_cimlxsw_pci_queue_doorbell_arm_consumer_ring(struct mlxsw_pci *mlxsw_pci, 2728c2ecf20Sopenharmony_ci struct mlxsw_pci_queue *q) 2738c2ecf20Sopenharmony_ci{ 2748c2ecf20Sopenharmony_ci wmb(); /* ensure all writes are done before we ring a bell */ 2758c2ecf20Sopenharmony_ci __mlxsw_pci_queue_doorbell_arm_set(mlxsw_pci, q, q->consumer_counter); 2768c2ecf20Sopenharmony_ci} 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_cistatic dma_addr_t __mlxsw_pci_queue_page_get(struct mlxsw_pci_queue *q, 2798c2ecf20Sopenharmony_ci int page_index) 2808c2ecf20Sopenharmony_ci{ 2818c2ecf20Sopenharmony_ci return q->mem_item.mapaddr + MLXSW_PCI_PAGE_SIZE * page_index; 2828c2ecf20Sopenharmony_ci} 2838c2ecf20Sopenharmony_ci 2848c2ecf20Sopenharmony_cistatic int mlxsw_pci_sdq_init(struct mlxsw_pci *mlxsw_pci, char *mbox, 2858c2ecf20Sopenharmony_ci struct mlxsw_pci_queue *q) 2868c2ecf20Sopenharmony_ci{ 2878c2ecf20Sopenharmony_ci int tclass; 2888c2ecf20Sopenharmony_ci int lp; 2898c2ecf20Sopenharmony_ci int i; 2908c2ecf20Sopenharmony_ci int err; 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_ci q->producer_counter = 0; 2938c2ecf20Sopenharmony_ci q->consumer_counter = 0; 2948c2ecf20Sopenharmony_ci tclass = q->num == MLXSW_PCI_SDQ_EMAD_INDEX ? MLXSW_PCI_SDQ_EMAD_TC : 2958c2ecf20Sopenharmony_ci MLXSW_PCI_SDQ_CTL_TC; 2968c2ecf20Sopenharmony_ci lp = q->num == MLXSW_PCI_SDQ_EMAD_INDEX ? MLXSW_CMD_MBOX_SW2HW_DQ_SDQ_LP_IGNORE_WQE : 2978c2ecf20Sopenharmony_ci MLXSW_CMD_MBOX_SW2HW_DQ_SDQ_LP_WQE; 2988c2ecf20Sopenharmony_ci 2998c2ecf20Sopenharmony_ci /* Set CQ of same number of this SDQ. */ 3008c2ecf20Sopenharmony_ci mlxsw_cmd_mbox_sw2hw_dq_cq_set(mbox, q->num); 3018c2ecf20Sopenharmony_ci mlxsw_cmd_mbox_sw2hw_dq_sdq_lp_set(mbox, lp); 3028c2ecf20Sopenharmony_ci mlxsw_cmd_mbox_sw2hw_dq_sdq_tclass_set(mbox, tclass); 3038c2ecf20Sopenharmony_ci mlxsw_cmd_mbox_sw2hw_dq_log2_dq_sz_set(mbox, 3); /* 8 pages */ 3048c2ecf20Sopenharmony_ci for (i = 0; i < MLXSW_PCI_AQ_PAGES; i++) { 3058c2ecf20Sopenharmony_ci dma_addr_t mapaddr = __mlxsw_pci_queue_page_get(q, i); 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_ci mlxsw_cmd_mbox_sw2hw_dq_pa_set(mbox, i, mapaddr); 3088c2ecf20Sopenharmony_ci } 3098c2ecf20Sopenharmony_ci 3108c2ecf20Sopenharmony_ci err = mlxsw_cmd_sw2hw_sdq(mlxsw_pci->core, mbox, q->num); 3118c2ecf20Sopenharmony_ci if (err) 3128c2ecf20Sopenharmony_ci return err; 3138c2ecf20Sopenharmony_ci mlxsw_pci_queue_doorbell_producer_ring(mlxsw_pci, q); 3148c2ecf20Sopenharmony_ci return 0; 3158c2ecf20Sopenharmony_ci} 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_cistatic void mlxsw_pci_sdq_fini(struct mlxsw_pci *mlxsw_pci, 3188c2ecf20Sopenharmony_ci struct mlxsw_pci_queue *q) 3198c2ecf20Sopenharmony_ci{ 3208c2ecf20Sopenharmony_ci mlxsw_cmd_hw2sw_sdq(mlxsw_pci->core, q->num); 3218c2ecf20Sopenharmony_ci} 3228c2ecf20Sopenharmony_ci 3238c2ecf20Sopenharmony_cistatic int mlxsw_pci_wqe_frag_map(struct mlxsw_pci *mlxsw_pci, char *wqe, 3248c2ecf20Sopenharmony_ci int index, char *frag_data, size_t frag_len, 3258c2ecf20Sopenharmony_ci int direction) 3268c2ecf20Sopenharmony_ci{ 3278c2ecf20Sopenharmony_ci struct pci_dev *pdev = mlxsw_pci->pdev; 3288c2ecf20Sopenharmony_ci dma_addr_t mapaddr; 3298c2ecf20Sopenharmony_ci 3308c2ecf20Sopenharmony_ci mapaddr = pci_map_single(pdev, frag_data, frag_len, direction); 3318c2ecf20Sopenharmony_ci if (unlikely(pci_dma_mapping_error(pdev, mapaddr))) { 3328c2ecf20Sopenharmony_ci dev_err_ratelimited(&pdev->dev, "failed to dma map tx frag\n"); 3338c2ecf20Sopenharmony_ci return -EIO; 3348c2ecf20Sopenharmony_ci } 3358c2ecf20Sopenharmony_ci mlxsw_pci_wqe_address_set(wqe, index, mapaddr); 3368c2ecf20Sopenharmony_ci mlxsw_pci_wqe_byte_count_set(wqe, index, frag_len); 3378c2ecf20Sopenharmony_ci return 0; 3388c2ecf20Sopenharmony_ci} 3398c2ecf20Sopenharmony_ci 3408c2ecf20Sopenharmony_cistatic void mlxsw_pci_wqe_frag_unmap(struct mlxsw_pci *mlxsw_pci, char *wqe, 3418c2ecf20Sopenharmony_ci int index, int direction) 3428c2ecf20Sopenharmony_ci{ 3438c2ecf20Sopenharmony_ci struct pci_dev *pdev = mlxsw_pci->pdev; 3448c2ecf20Sopenharmony_ci size_t frag_len = mlxsw_pci_wqe_byte_count_get(wqe, index); 3458c2ecf20Sopenharmony_ci dma_addr_t mapaddr = mlxsw_pci_wqe_address_get(wqe, index); 3468c2ecf20Sopenharmony_ci 3478c2ecf20Sopenharmony_ci if (!frag_len) 3488c2ecf20Sopenharmony_ci return; 3498c2ecf20Sopenharmony_ci pci_unmap_single(pdev, mapaddr, frag_len, direction); 3508c2ecf20Sopenharmony_ci} 3518c2ecf20Sopenharmony_ci 3528c2ecf20Sopenharmony_cistatic int mlxsw_pci_rdq_skb_alloc(struct mlxsw_pci *mlxsw_pci, 3538c2ecf20Sopenharmony_ci struct mlxsw_pci_queue_elem_info *elem_info) 3548c2ecf20Sopenharmony_ci{ 3558c2ecf20Sopenharmony_ci size_t buf_len = MLXSW_PORT_MAX_MTU; 3568c2ecf20Sopenharmony_ci char *wqe = elem_info->elem; 3578c2ecf20Sopenharmony_ci struct sk_buff *skb; 3588c2ecf20Sopenharmony_ci int err; 3598c2ecf20Sopenharmony_ci 3608c2ecf20Sopenharmony_ci skb = netdev_alloc_skb_ip_align(NULL, buf_len); 3618c2ecf20Sopenharmony_ci if (!skb) 3628c2ecf20Sopenharmony_ci return -ENOMEM; 3638c2ecf20Sopenharmony_ci 3648c2ecf20Sopenharmony_ci err = mlxsw_pci_wqe_frag_map(mlxsw_pci, wqe, 0, skb->data, 3658c2ecf20Sopenharmony_ci buf_len, DMA_FROM_DEVICE); 3668c2ecf20Sopenharmony_ci if (err) 3678c2ecf20Sopenharmony_ci goto err_frag_map; 3688c2ecf20Sopenharmony_ci 3698c2ecf20Sopenharmony_ci elem_info->u.rdq.skb = skb; 3708c2ecf20Sopenharmony_ci return 0; 3718c2ecf20Sopenharmony_ci 3728c2ecf20Sopenharmony_cierr_frag_map: 3738c2ecf20Sopenharmony_ci dev_kfree_skb_any(skb); 3748c2ecf20Sopenharmony_ci return err; 3758c2ecf20Sopenharmony_ci} 3768c2ecf20Sopenharmony_ci 3778c2ecf20Sopenharmony_cistatic void mlxsw_pci_rdq_skb_free(struct mlxsw_pci *mlxsw_pci, 3788c2ecf20Sopenharmony_ci struct mlxsw_pci_queue_elem_info *elem_info) 3798c2ecf20Sopenharmony_ci{ 3808c2ecf20Sopenharmony_ci struct sk_buff *skb; 3818c2ecf20Sopenharmony_ci char *wqe; 3828c2ecf20Sopenharmony_ci 3838c2ecf20Sopenharmony_ci skb = elem_info->u.rdq.skb; 3848c2ecf20Sopenharmony_ci wqe = elem_info->elem; 3858c2ecf20Sopenharmony_ci 3868c2ecf20Sopenharmony_ci mlxsw_pci_wqe_frag_unmap(mlxsw_pci, wqe, 0, DMA_FROM_DEVICE); 3878c2ecf20Sopenharmony_ci dev_kfree_skb_any(skb); 3888c2ecf20Sopenharmony_ci} 3898c2ecf20Sopenharmony_ci 3908c2ecf20Sopenharmony_cistatic int mlxsw_pci_rdq_init(struct mlxsw_pci *mlxsw_pci, char *mbox, 3918c2ecf20Sopenharmony_ci struct mlxsw_pci_queue *q) 3928c2ecf20Sopenharmony_ci{ 3938c2ecf20Sopenharmony_ci struct mlxsw_pci_queue_elem_info *elem_info; 3948c2ecf20Sopenharmony_ci u8 sdq_count = mlxsw_pci_sdq_count(mlxsw_pci); 3958c2ecf20Sopenharmony_ci int i; 3968c2ecf20Sopenharmony_ci int err; 3978c2ecf20Sopenharmony_ci 3988c2ecf20Sopenharmony_ci q->producer_counter = 0; 3998c2ecf20Sopenharmony_ci q->consumer_counter = 0; 4008c2ecf20Sopenharmony_ci 4018c2ecf20Sopenharmony_ci /* Set CQ of same number of this RDQ with base 4028c2ecf20Sopenharmony_ci * above SDQ count as the lower ones are assigned to SDQs. 4038c2ecf20Sopenharmony_ci */ 4048c2ecf20Sopenharmony_ci mlxsw_cmd_mbox_sw2hw_dq_cq_set(mbox, sdq_count + q->num); 4058c2ecf20Sopenharmony_ci mlxsw_cmd_mbox_sw2hw_dq_log2_dq_sz_set(mbox, 3); /* 8 pages */ 4068c2ecf20Sopenharmony_ci for (i = 0; i < MLXSW_PCI_AQ_PAGES; i++) { 4078c2ecf20Sopenharmony_ci dma_addr_t mapaddr = __mlxsw_pci_queue_page_get(q, i); 4088c2ecf20Sopenharmony_ci 4098c2ecf20Sopenharmony_ci mlxsw_cmd_mbox_sw2hw_dq_pa_set(mbox, i, mapaddr); 4108c2ecf20Sopenharmony_ci } 4118c2ecf20Sopenharmony_ci 4128c2ecf20Sopenharmony_ci err = mlxsw_cmd_sw2hw_rdq(mlxsw_pci->core, mbox, q->num); 4138c2ecf20Sopenharmony_ci if (err) 4148c2ecf20Sopenharmony_ci return err; 4158c2ecf20Sopenharmony_ci 4168c2ecf20Sopenharmony_ci mlxsw_pci_queue_doorbell_producer_ring(mlxsw_pci, q); 4178c2ecf20Sopenharmony_ci 4188c2ecf20Sopenharmony_ci for (i = 0; i < q->count; i++) { 4198c2ecf20Sopenharmony_ci elem_info = mlxsw_pci_queue_elem_info_producer_get(q); 4208c2ecf20Sopenharmony_ci BUG_ON(!elem_info); 4218c2ecf20Sopenharmony_ci err = mlxsw_pci_rdq_skb_alloc(mlxsw_pci, elem_info); 4228c2ecf20Sopenharmony_ci if (err) 4238c2ecf20Sopenharmony_ci goto rollback; 4248c2ecf20Sopenharmony_ci /* Everything is set up, ring doorbell to pass elem to HW */ 4258c2ecf20Sopenharmony_ci q->producer_counter++; 4268c2ecf20Sopenharmony_ci mlxsw_pci_queue_doorbell_producer_ring(mlxsw_pci, q); 4278c2ecf20Sopenharmony_ci } 4288c2ecf20Sopenharmony_ci 4298c2ecf20Sopenharmony_ci return 0; 4308c2ecf20Sopenharmony_ci 4318c2ecf20Sopenharmony_cirollback: 4328c2ecf20Sopenharmony_ci for (i--; i >= 0; i--) { 4338c2ecf20Sopenharmony_ci elem_info = mlxsw_pci_queue_elem_info_get(q, i); 4348c2ecf20Sopenharmony_ci mlxsw_pci_rdq_skb_free(mlxsw_pci, elem_info); 4358c2ecf20Sopenharmony_ci } 4368c2ecf20Sopenharmony_ci mlxsw_cmd_hw2sw_rdq(mlxsw_pci->core, q->num); 4378c2ecf20Sopenharmony_ci 4388c2ecf20Sopenharmony_ci return err; 4398c2ecf20Sopenharmony_ci} 4408c2ecf20Sopenharmony_ci 4418c2ecf20Sopenharmony_cistatic void mlxsw_pci_rdq_fini(struct mlxsw_pci *mlxsw_pci, 4428c2ecf20Sopenharmony_ci struct mlxsw_pci_queue *q) 4438c2ecf20Sopenharmony_ci{ 4448c2ecf20Sopenharmony_ci struct mlxsw_pci_queue_elem_info *elem_info; 4458c2ecf20Sopenharmony_ci int i; 4468c2ecf20Sopenharmony_ci 4478c2ecf20Sopenharmony_ci mlxsw_cmd_hw2sw_rdq(mlxsw_pci->core, q->num); 4488c2ecf20Sopenharmony_ci for (i = 0; i < q->count; i++) { 4498c2ecf20Sopenharmony_ci elem_info = mlxsw_pci_queue_elem_info_get(q, i); 4508c2ecf20Sopenharmony_ci mlxsw_pci_rdq_skb_free(mlxsw_pci, elem_info); 4518c2ecf20Sopenharmony_ci } 4528c2ecf20Sopenharmony_ci} 4538c2ecf20Sopenharmony_ci 4548c2ecf20Sopenharmony_cistatic void mlxsw_pci_cq_pre_init(struct mlxsw_pci *mlxsw_pci, 4558c2ecf20Sopenharmony_ci struct mlxsw_pci_queue *q) 4568c2ecf20Sopenharmony_ci{ 4578c2ecf20Sopenharmony_ci q->u.cq.v = mlxsw_pci->max_cqe_ver; 4588c2ecf20Sopenharmony_ci 4598c2ecf20Sopenharmony_ci /* For SDQ it is pointless to use CQEv2, so use CQEv1 instead */ 4608c2ecf20Sopenharmony_ci if (q->u.cq.v == MLXSW_PCI_CQE_V2 && 4618c2ecf20Sopenharmony_ci q->num < mlxsw_pci->num_sdq_cqs) 4628c2ecf20Sopenharmony_ci q->u.cq.v = MLXSW_PCI_CQE_V1; 4638c2ecf20Sopenharmony_ci} 4648c2ecf20Sopenharmony_ci 4658c2ecf20Sopenharmony_cistatic int mlxsw_pci_cq_init(struct mlxsw_pci *mlxsw_pci, char *mbox, 4668c2ecf20Sopenharmony_ci struct mlxsw_pci_queue *q) 4678c2ecf20Sopenharmony_ci{ 4688c2ecf20Sopenharmony_ci int i; 4698c2ecf20Sopenharmony_ci int err; 4708c2ecf20Sopenharmony_ci 4718c2ecf20Sopenharmony_ci q->consumer_counter = 0; 4728c2ecf20Sopenharmony_ci 4738c2ecf20Sopenharmony_ci for (i = 0; i < q->count; i++) { 4748c2ecf20Sopenharmony_ci char *elem = mlxsw_pci_queue_elem_get(q, i); 4758c2ecf20Sopenharmony_ci 4768c2ecf20Sopenharmony_ci mlxsw_pci_cqe_owner_set(q->u.cq.v, elem, 1); 4778c2ecf20Sopenharmony_ci } 4788c2ecf20Sopenharmony_ci 4798c2ecf20Sopenharmony_ci if (q->u.cq.v == MLXSW_PCI_CQE_V1) 4808c2ecf20Sopenharmony_ci mlxsw_cmd_mbox_sw2hw_cq_cqe_ver_set(mbox, 4818c2ecf20Sopenharmony_ci MLXSW_CMD_MBOX_SW2HW_CQ_CQE_VER_1); 4828c2ecf20Sopenharmony_ci else if (q->u.cq.v == MLXSW_PCI_CQE_V2) 4838c2ecf20Sopenharmony_ci mlxsw_cmd_mbox_sw2hw_cq_cqe_ver_set(mbox, 4848c2ecf20Sopenharmony_ci MLXSW_CMD_MBOX_SW2HW_CQ_CQE_VER_2); 4858c2ecf20Sopenharmony_ci 4868c2ecf20Sopenharmony_ci mlxsw_cmd_mbox_sw2hw_cq_c_eqn_set(mbox, MLXSW_PCI_EQ_COMP_NUM); 4878c2ecf20Sopenharmony_ci mlxsw_cmd_mbox_sw2hw_cq_st_set(mbox, 0); 4888c2ecf20Sopenharmony_ci mlxsw_cmd_mbox_sw2hw_cq_log_cq_size_set(mbox, ilog2(q->count)); 4898c2ecf20Sopenharmony_ci for (i = 0; i < MLXSW_PCI_AQ_PAGES; i++) { 4908c2ecf20Sopenharmony_ci dma_addr_t mapaddr = __mlxsw_pci_queue_page_get(q, i); 4918c2ecf20Sopenharmony_ci 4928c2ecf20Sopenharmony_ci mlxsw_cmd_mbox_sw2hw_cq_pa_set(mbox, i, mapaddr); 4938c2ecf20Sopenharmony_ci } 4948c2ecf20Sopenharmony_ci err = mlxsw_cmd_sw2hw_cq(mlxsw_pci->core, mbox, q->num); 4958c2ecf20Sopenharmony_ci if (err) 4968c2ecf20Sopenharmony_ci return err; 4978c2ecf20Sopenharmony_ci mlxsw_pci_queue_doorbell_consumer_ring(mlxsw_pci, q); 4988c2ecf20Sopenharmony_ci mlxsw_pci_queue_doorbell_arm_consumer_ring(mlxsw_pci, q); 4998c2ecf20Sopenharmony_ci return 0; 5008c2ecf20Sopenharmony_ci} 5018c2ecf20Sopenharmony_ci 5028c2ecf20Sopenharmony_cistatic void mlxsw_pci_cq_fini(struct mlxsw_pci *mlxsw_pci, 5038c2ecf20Sopenharmony_ci struct mlxsw_pci_queue *q) 5048c2ecf20Sopenharmony_ci{ 5058c2ecf20Sopenharmony_ci mlxsw_cmd_hw2sw_cq(mlxsw_pci->core, q->num); 5068c2ecf20Sopenharmony_ci} 5078c2ecf20Sopenharmony_ci 5088c2ecf20Sopenharmony_cistatic void mlxsw_pci_cqe_sdq_handle(struct mlxsw_pci *mlxsw_pci, 5098c2ecf20Sopenharmony_ci struct mlxsw_pci_queue *q, 5108c2ecf20Sopenharmony_ci u16 consumer_counter_limit, 5118c2ecf20Sopenharmony_ci char *cqe) 5128c2ecf20Sopenharmony_ci{ 5138c2ecf20Sopenharmony_ci struct pci_dev *pdev = mlxsw_pci->pdev; 5148c2ecf20Sopenharmony_ci struct mlxsw_pci_queue_elem_info *elem_info; 5158c2ecf20Sopenharmony_ci struct mlxsw_tx_info tx_info; 5168c2ecf20Sopenharmony_ci char *wqe; 5178c2ecf20Sopenharmony_ci struct sk_buff *skb; 5188c2ecf20Sopenharmony_ci int i; 5198c2ecf20Sopenharmony_ci 5208c2ecf20Sopenharmony_ci spin_lock(&q->lock); 5218c2ecf20Sopenharmony_ci elem_info = mlxsw_pci_queue_elem_info_consumer_get(q); 5228c2ecf20Sopenharmony_ci tx_info = mlxsw_skb_cb(elem_info->u.sdq.skb)->tx_info; 5238c2ecf20Sopenharmony_ci skb = elem_info->u.sdq.skb; 5248c2ecf20Sopenharmony_ci wqe = elem_info->elem; 5258c2ecf20Sopenharmony_ci for (i = 0; i < MLXSW_PCI_WQE_SG_ENTRIES; i++) 5268c2ecf20Sopenharmony_ci mlxsw_pci_wqe_frag_unmap(mlxsw_pci, wqe, i, DMA_TO_DEVICE); 5278c2ecf20Sopenharmony_ci 5288c2ecf20Sopenharmony_ci if (unlikely(!tx_info.is_emad && 5298c2ecf20Sopenharmony_ci skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP)) { 5308c2ecf20Sopenharmony_ci mlxsw_core_ptp_transmitted(mlxsw_pci->core, skb, 5318c2ecf20Sopenharmony_ci tx_info.local_port); 5328c2ecf20Sopenharmony_ci skb = NULL; 5338c2ecf20Sopenharmony_ci } 5348c2ecf20Sopenharmony_ci 5358c2ecf20Sopenharmony_ci if (skb) 5368c2ecf20Sopenharmony_ci dev_kfree_skb_any(skb); 5378c2ecf20Sopenharmony_ci elem_info->u.sdq.skb = NULL; 5388c2ecf20Sopenharmony_ci 5398c2ecf20Sopenharmony_ci if (q->consumer_counter++ != consumer_counter_limit) 5408c2ecf20Sopenharmony_ci dev_dbg_ratelimited(&pdev->dev, "Consumer counter does not match limit in SDQ\n"); 5418c2ecf20Sopenharmony_ci spin_unlock(&q->lock); 5428c2ecf20Sopenharmony_ci} 5438c2ecf20Sopenharmony_ci 5448c2ecf20Sopenharmony_cistatic void mlxsw_pci_cqe_rdq_handle(struct mlxsw_pci *mlxsw_pci, 5458c2ecf20Sopenharmony_ci struct mlxsw_pci_queue *q, 5468c2ecf20Sopenharmony_ci u16 consumer_counter_limit, 5478c2ecf20Sopenharmony_ci enum mlxsw_pci_cqe_v cqe_v, char *cqe) 5488c2ecf20Sopenharmony_ci{ 5498c2ecf20Sopenharmony_ci struct pci_dev *pdev = mlxsw_pci->pdev; 5508c2ecf20Sopenharmony_ci struct mlxsw_pci_queue_elem_info *elem_info; 5518c2ecf20Sopenharmony_ci struct mlxsw_rx_info rx_info = {}; 5528c2ecf20Sopenharmony_ci char wqe[MLXSW_PCI_WQE_SIZE]; 5538c2ecf20Sopenharmony_ci struct sk_buff *skb; 5548c2ecf20Sopenharmony_ci u16 byte_count; 5558c2ecf20Sopenharmony_ci int err; 5568c2ecf20Sopenharmony_ci 5578c2ecf20Sopenharmony_ci elem_info = mlxsw_pci_queue_elem_info_consumer_get(q); 5588c2ecf20Sopenharmony_ci skb = elem_info->u.rdq.skb; 5598c2ecf20Sopenharmony_ci memcpy(wqe, elem_info->elem, MLXSW_PCI_WQE_SIZE); 5608c2ecf20Sopenharmony_ci 5618c2ecf20Sopenharmony_ci if (q->consumer_counter++ != consumer_counter_limit) 5628c2ecf20Sopenharmony_ci dev_dbg_ratelimited(&pdev->dev, "Consumer counter does not match limit in RDQ\n"); 5638c2ecf20Sopenharmony_ci 5648c2ecf20Sopenharmony_ci err = mlxsw_pci_rdq_skb_alloc(mlxsw_pci, elem_info); 5658c2ecf20Sopenharmony_ci if (err) { 5668c2ecf20Sopenharmony_ci dev_err_ratelimited(&pdev->dev, "Failed to alloc skb for RDQ\n"); 5678c2ecf20Sopenharmony_ci goto out; 5688c2ecf20Sopenharmony_ci } 5698c2ecf20Sopenharmony_ci 5708c2ecf20Sopenharmony_ci mlxsw_pci_wqe_frag_unmap(mlxsw_pci, wqe, 0, DMA_FROM_DEVICE); 5718c2ecf20Sopenharmony_ci 5728c2ecf20Sopenharmony_ci if (mlxsw_pci_cqe_lag_get(cqe_v, cqe)) { 5738c2ecf20Sopenharmony_ci rx_info.is_lag = true; 5748c2ecf20Sopenharmony_ci rx_info.u.lag_id = mlxsw_pci_cqe_lag_id_get(cqe_v, cqe); 5758c2ecf20Sopenharmony_ci rx_info.lag_port_index = 5768c2ecf20Sopenharmony_ci mlxsw_pci_cqe_lag_subport_get(cqe_v, cqe); 5778c2ecf20Sopenharmony_ci } else { 5788c2ecf20Sopenharmony_ci rx_info.is_lag = false; 5798c2ecf20Sopenharmony_ci rx_info.u.sys_port = mlxsw_pci_cqe_system_port_get(cqe); 5808c2ecf20Sopenharmony_ci } 5818c2ecf20Sopenharmony_ci 5828c2ecf20Sopenharmony_ci rx_info.trap_id = mlxsw_pci_cqe_trap_id_get(cqe); 5838c2ecf20Sopenharmony_ci 5848c2ecf20Sopenharmony_ci if (rx_info.trap_id == MLXSW_TRAP_ID_DISCARD_INGRESS_ACL || 5858c2ecf20Sopenharmony_ci rx_info.trap_id == MLXSW_TRAP_ID_DISCARD_EGRESS_ACL) { 5868c2ecf20Sopenharmony_ci u32 cookie_index = 0; 5878c2ecf20Sopenharmony_ci 5888c2ecf20Sopenharmony_ci if (mlxsw_pci->max_cqe_ver >= MLXSW_PCI_CQE_V2) 5898c2ecf20Sopenharmony_ci cookie_index = mlxsw_pci_cqe2_user_def_val_orig_pkt_len_get(cqe); 5908c2ecf20Sopenharmony_ci mlxsw_skb_cb(skb)->cookie_index = cookie_index; 5918c2ecf20Sopenharmony_ci } else if (rx_info.trap_id >= MLXSW_TRAP_ID_MIRROR_SESSION0 && 5928c2ecf20Sopenharmony_ci rx_info.trap_id <= MLXSW_TRAP_ID_MIRROR_SESSION7 && 5938c2ecf20Sopenharmony_ci mlxsw_pci->max_cqe_ver >= MLXSW_PCI_CQE_V2) { 5948c2ecf20Sopenharmony_ci rx_info.mirror_reason = mlxsw_pci_cqe2_mirror_reason_get(cqe); 5958c2ecf20Sopenharmony_ci } 5968c2ecf20Sopenharmony_ci 5978c2ecf20Sopenharmony_ci byte_count = mlxsw_pci_cqe_byte_count_get(cqe); 5988c2ecf20Sopenharmony_ci if (mlxsw_pci_cqe_crc_get(cqe_v, cqe)) 5998c2ecf20Sopenharmony_ci byte_count -= ETH_FCS_LEN; 6008c2ecf20Sopenharmony_ci skb_put(skb, byte_count); 6018c2ecf20Sopenharmony_ci mlxsw_core_skb_receive(mlxsw_pci->core, skb, &rx_info); 6028c2ecf20Sopenharmony_ci 6038c2ecf20Sopenharmony_ciout: 6048c2ecf20Sopenharmony_ci /* Everything is set up, ring doorbell to pass elem to HW */ 6058c2ecf20Sopenharmony_ci q->producer_counter++; 6068c2ecf20Sopenharmony_ci mlxsw_pci_queue_doorbell_producer_ring(mlxsw_pci, q); 6078c2ecf20Sopenharmony_ci return; 6088c2ecf20Sopenharmony_ci} 6098c2ecf20Sopenharmony_ci 6108c2ecf20Sopenharmony_cistatic char *mlxsw_pci_cq_sw_cqe_get(struct mlxsw_pci_queue *q) 6118c2ecf20Sopenharmony_ci{ 6128c2ecf20Sopenharmony_ci struct mlxsw_pci_queue_elem_info *elem_info; 6138c2ecf20Sopenharmony_ci char *elem; 6148c2ecf20Sopenharmony_ci bool owner_bit; 6158c2ecf20Sopenharmony_ci 6168c2ecf20Sopenharmony_ci elem_info = mlxsw_pci_queue_elem_info_consumer_get(q); 6178c2ecf20Sopenharmony_ci elem = elem_info->elem; 6188c2ecf20Sopenharmony_ci owner_bit = mlxsw_pci_cqe_owner_get(q->u.cq.v, elem); 6198c2ecf20Sopenharmony_ci if (mlxsw_pci_elem_hw_owned(q, owner_bit)) 6208c2ecf20Sopenharmony_ci return NULL; 6218c2ecf20Sopenharmony_ci q->consumer_counter++; 6228c2ecf20Sopenharmony_ci rmb(); /* make sure we read owned bit before the rest of elem */ 6238c2ecf20Sopenharmony_ci return elem; 6248c2ecf20Sopenharmony_ci} 6258c2ecf20Sopenharmony_ci 6268c2ecf20Sopenharmony_cistatic void mlxsw_pci_cq_tasklet(struct tasklet_struct *t) 6278c2ecf20Sopenharmony_ci{ 6288c2ecf20Sopenharmony_ci struct mlxsw_pci_queue *q = from_tasklet(q, t, tasklet); 6298c2ecf20Sopenharmony_ci struct mlxsw_pci *mlxsw_pci = q->pci; 6308c2ecf20Sopenharmony_ci char *cqe; 6318c2ecf20Sopenharmony_ci int items = 0; 6328c2ecf20Sopenharmony_ci int credits = q->count >> 1; 6338c2ecf20Sopenharmony_ci 6348c2ecf20Sopenharmony_ci while ((cqe = mlxsw_pci_cq_sw_cqe_get(q))) { 6358c2ecf20Sopenharmony_ci u16 wqe_counter = mlxsw_pci_cqe_wqe_counter_get(cqe); 6368c2ecf20Sopenharmony_ci u8 sendq = mlxsw_pci_cqe_sr_get(q->u.cq.v, cqe); 6378c2ecf20Sopenharmony_ci u8 dqn = mlxsw_pci_cqe_dqn_get(q->u.cq.v, cqe); 6388c2ecf20Sopenharmony_ci char ncqe[MLXSW_PCI_CQE_SIZE_MAX]; 6398c2ecf20Sopenharmony_ci 6408c2ecf20Sopenharmony_ci memcpy(ncqe, cqe, q->elem_size); 6418c2ecf20Sopenharmony_ci mlxsw_pci_queue_doorbell_consumer_ring(mlxsw_pci, q); 6428c2ecf20Sopenharmony_ci 6438c2ecf20Sopenharmony_ci if (sendq) { 6448c2ecf20Sopenharmony_ci struct mlxsw_pci_queue *sdq; 6458c2ecf20Sopenharmony_ci 6468c2ecf20Sopenharmony_ci sdq = mlxsw_pci_sdq_get(mlxsw_pci, dqn); 6478c2ecf20Sopenharmony_ci mlxsw_pci_cqe_sdq_handle(mlxsw_pci, sdq, 6488c2ecf20Sopenharmony_ci wqe_counter, ncqe); 6498c2ecf20Sopenharmony_ci q->u.cq.comp_sdq_count++; 6508c2ecf20Sopenharmony_ci } else { 6518c2ecf20Sopenharmony_ci struct mlxsw_pci_queue *rdq; 6528c2ecf20Sopenharmony_ci 6538c2ecf20Sopenharmony_ci rdq = mlxsw_pci_rdq_get(mlxsw_pci, dqn); 6548c2ecf20Sopenharmony_ci mlxsw_pci_cqe_rdq_handle(mlxsw_pci, rdq, 6558c2ecf20Sopenharmony_ci wqe_counter, q->u.cq.v, ncqe); 6568c2ecf20Sopenharmony_ci q->u.cq.comp_rdq_count++; 6578c2ecf20Sopenharmony_ci } 6588c2ecf20Sopenharmony_ci if (++items == credits) 6598c2ecf20Sopenharmony_ci break; 6608c2ecf20Sopenharmony_ci } 6618c2ecf20Sopenharmony_ci if (items) 6628c2ecf20Sopenharmony_ci mlxsw_pci_queue_doorbell_arm_consumer_ring(mlxsw_pci, q); 6638c2ecf20Sopenharmony_ci} 6648c2ecf20Sopenharmony_ci 6658c2ecf20Sopenharmony_cistatic u16 mlxsw_pci_cq_elem_count(const struct mlxsw_pci_queue *q) 6668c2ecf20Sopenharmony_ci{ 6678c2ecf20Sopenharmony_ci return q->u.cq.v == MLXSW_PCI_CQE_V2 ? MLXSW_PCI_CQE2_COUNT : 6688c2ecf20Sopenharmony_ci MLXSW_PCI_CQE01_COUNT; 6698c2ecf20Sopenharmony_ci} 6708c2ecf20Sopenharmony_ci 6718c2ecf20Sopenharmony_cistatic u8 mlxsw_pci_cq_elem_size(const struct mlxsw_pci_queue *q) 6728c2ecf20Sopenharmony_ci{ 6738c2ecf20Sopenharmony_ci return q->u.cq.v == MLXSW_PCI_CQE_V2 ? MLXSW_PCI_CQE2_SIZE : 6748c2ecf20Sopenharmony_ci MLXSW_PCI_CQE01_SIZE; 6758c2ecf20Sopenharmony_ci} 6768c2ecf20Sopenharmony_ci 6778c2ecf20Sopenharmony_cistatic int mlxsw_pci_eq_init(struct mlxsw_pci *mlxsw_pci, char *mbox, 6788c2ecf20Sopenharmony_ci struct mlxsw_pci_queue *q) 6798c2ecf20Sopenharmony_ci{ 6808c2ecf20Sopenharmony_ci int i; 6818c2ecf20Sopenharmony_ci int err; 6828c2ecf20Sopenharmony_ci 6838c2ecf20Sopenharmony_ci q->consumer_counter = 0; 6848c2ecf20Sopenharmony_ci 6858c2ecf20Sopenharmony_ci for (i = 0; i < q->count; i++) { 6868c2ecf20Sopenharmony_ci char *elem = mlxsw_pci_queue_elem_get(q, i); 6878c2ecf20Sopenharmony_ci 6888c2ecf20Sopenharmony_ci mlxsw_pci_eqe_owner_set(elem, 1); 6898c2ecf20Sopenharmony_ci } 6908c2ecf20Sopenharmony_ci 6918c2ecf20Sopenharmony_ci mlxsw_cmd_mbox_sw2hw_eq_int_msix_set(mbox, 1); /* MSI-X used */ 6928c2ecf20Sopenharmony_ci mlxsw_cmd_mbox_sw2hw_eq_st_set(mbox, 1); /* armed */ 6938c2ecf20Sopenharmony_ci mlxsw_cmd_mbox_sw2hw_eq_log_eq_size_set(mbox, ilog2(q->count)); 6948c2ecf20Sopenharmony_ci for (i = 0; i < MLXSW_PCI_AQ_PAGES; i++) { 6958c2ecf20Sopenharmony_ci dma_addr_t mapaddr = __mlxsw_pci_queue_page_get(q, i); 6968c2ecf20Sopenharmony_ci 6978c2ecf20Sopenharmony_ci mlxsw_cmd_mbox_sw2hw_eq_pa_set(mbox, i, mapaddr); 6988c2ecf20Sopenharmony_ci } 6998c2ecf20Sopenharmony_ci err = mlxsw_cmd_sw2hw_eq(mlxsw_pci->core, mbox, q->num); 7008c2ecf20Sopenharmony_ci if (err) 7018c2ecf20Sopenharmony_ci return err; 7028c2ecf20Sopenharmony_ci mlxsw_pci_queue_doorbell_consumer_ring(mlxsw_pci, q); 7038c2ecf20Sopenharmony_ci mlxsw_pci_queue_doorbell_arm_consumer_ring(mlxsw_pci, q); 7048c2ecf20Sopenharmony_ci return 0; 7058c2ecf20Sopenharmony_ci} 7068c2ecf20Sopenharmony_ci 7078c2ecf20Sopenharmony_cistatic void mlxsw_pci_eq_fini(struct mlxsw_pci *mlxsw_pci, 7088c2ecf20Sopenharmony_ci struct mlxsw_pci_queue *q) 7098c2ecf20Sopenharmony_ci{ 7108c2ecf20Sopenharmony_ci mlxsw_cmd_hw2sw_eq(mlxsw_pci->core, q->num); 7118c2ecf20Sopenharmony_ci} 7128c2ecf20Sopenharmony_ci 7138c2ecf20Sopenharmony_cistatic void mlxsw_pci_eq_cmd_event(struct mlxsw_pci *mlxsw_pci, char *eqe) 7148c2ecf20Sopenharmony_ci{ 7158c2ecf20Sopenharmony_ci mlxsw_pci->cmd.comp.status = mlxsw_pci_eqe_cmd_status_get(eqe); 7168c2ecf20Sopenharmony_ci mlxsw_pci->cmd.comp.out_param = 7178c2ecf20Sopenharmony_ci ((u64) mlxsw_pci_eqe_cmd_out_param_h_get(eqe)) << 32 | 7188c2ecf20Sopenharmony_ci mlxsw_pci_eqe_cmd_out_param_l_get(eqe); 7198c2ecf20Sopenharmony_ci mlxsw_pci->cmd.wait_done = true; 7208c2ecf20Sopenharmony_ci wake_up(&mlxsw_pci->cmd.wait); 7218c2ecf20Sopenharmony_ci} 7228c2ecf20Sopenharmony_ci 7238c2ecf20Sopenharmony_cistatic char *mlxsw_pci_eq_sw_eqe_get(struct mlxsw_pci_queue *q) 7248c2ecf20Sopenharmony_ci{ 7258c2ecf20Sopenharmony_ci struct mlxsw_pci_queue_elem_info *elem_info; 7268c2ecf20Sopenharmony_ci char *elem; 7278c2ecf20Sopenharmony_ci bool owner_bit; 7288c2ecf20Sopenharmony_ci 7298c2ecf20Sopenharmony_ci elem_info = mlxsw_pci_queue_elem_info_consumer_get(q); 7308c2ecf20Sopenharmony_ci elem = elem_info->elem; 7318c2ecf20Sopenharmony_ci owner_bit = mlxsw_pci_eqe_owner_get(elem); 7328c2ecf20Sopenharmony_ci if (mlxsw_pci_elem_hw_owned(q, owner_bit)) 7338c2ecf20Sopenharmony_ci return NULL; 7348c2ecf20Sopenharmony_ci q->consumer_counter++; 7358c2ecf20Sopenharmony_ci rmb(); /* make sure we read owned bit before the rest of elem */ 7368c2ecf20Sopenharmony_ci return elem; 7378c2ecf20Sopenharmony_ci} 7388c2ecf20Sopenharmony_ci 7398c2ecf20Sopenharmony_cistatic void mlxsw_pci_eq_tasklet(struct tasklet_struct *t) 7408c2ecf20Sopenharmony_ci{ 7418c2ecf20Sopenharmony_ci struct mlxsw_pci_queue *q = from_tasklet(q, t, tasklet); 7428c2ecf20Sopenharmony_ci struct mlxsw_pci *mlxsw_pci = q->pci; 7438c2ecf20Sopenharmony_ci u8 cq_count = mlxsw_pci_cq_count(mlxsw_pci); 7448c2ecf20Sopenharmony_ci unsigned long active_cqns[BITS_TO_LONGS(MLXSW_PCI_CQS_MAX)]; 7458c2ecf20Sopenharmony_ci char *eqe; 7468c2ecf20Sopenharmony_ci u8 cqn; 7478c2ecf20Sopenharmony_ci bool cq_handle = false; 7488c2ecf20Sopenharmony_ci int items = 0; 7498c2ecf20Sopenharmony_ci int credits = q->count >> 1; 7508c2ecf20Sopenharmony_ci 7518c2ecf20Sopenharmony_ci memset(&active_cqns, 0, sizeof(active_cqns)); 7528c2ecf20Sopenharmony_ci 7538c2ecf20Sopenharmony_ci while ((eqe = mlxsw_pci_eq_sw_eqe_get(q))) { 7548c2ecf20Sopenharmony_ci 7558c2ecf20Sopenharmony_ci /* Command interface completion events are always received on 7568c2ecf20Sopenharmony_ci * queue MLXSW_PCI_EQ_ASYNC_NUM (EQ0) and completion events 7578c2ecf20Sopenharmony_ci * are mapped to queue MLXSW_PCI_EQ_COMP_NUM (EQ1). 7588c2ecf20Sopenharmony_ci */ 7598c2ecf20Sopenharmony_ci switch (q->num) { 7608c2ecf20Sopenharmony_ci case MLXSW_PCI_EQ_ASYNC_NUM: 7618c2ecf20Sopenharmony_ci mlxsw_pci_eq_cmd_event(mlxsw_pci, eqe); 7628c2ecf20Sopenharmony_ci q->u.eq.ev_cmd_count++; 7638c2ecf20Sopenharmony_ci break; 7648c2ecf20Sopenharmony_ci case MLXSW_PCI_EQ_COMP_NUM: 7658c2ecf20Sopenharmony_ci cqn = mlxsw_pci_eqe_cqn_get(eqe); 7668c2ecf20Sopenharmony_ci set_bit(cqn, active_cqns); 7678c2ecf20Sopenharmony_ci cq_handle = true; 7688c2ecf20Sopenharmony_ci q->u.eq.ev_comp_count++; 7698c2ecf20Sopenharmony_ci break; 7708c2ecf20Sopenharmony_ci default: 7718c2ecf20Sopenharmony_ci q->u.eq.ev_other_count++; 7728c2ecf20Sopenharmony_ci } 7738c2ecf20Sopenharmony_ci if (++items == credits) 7748c2ecf20Sopenharmony_ci break; 7758c2ecf20Sopenharmony_ci } 7768c2ecf20Sopenharmony_ci if (items) { 7778c2ecf20Sopenharmony_ci mlxsw_pci_queue_doorbell_consumer_ring(mlxsw_pci, q); 7788c2ecf20Sopenharmony_ci mlxsw_pci_queue_doorbell_arm_consumer_ring(mlxsw_pci, q); 7798c2ecf20Sopenharmony_ci } 7808c2ecf20Sopenharmony_ci 7818c2ecf20Sopenharmony_ci if (!cq_handle) 7828c2ecf20Sopenharmony_ci return; 7838c2ecf20Sopenharmony_ci for_each_set_bit(cqn, active_cqns, cq_count) { 7848c2ecf20Sopenharmony_ci q = mlxsw_pci_cq_get(mlxsw_pci, cqn); 7858c2ecf20Sopenharmony_ci mlxsw_pci_queue_tasklet_schedule(q); 7868c2ecf20Sopenharmony_ci } 7878c2ecf20Sopenharmony_ci} 7888c2ecf20Sopenharmony_ci 7898c2ecf20Sopenharmony_cistruct mlxsw_pci_queue_ops { 7908c2ecf20Sopenharmony_ci const char *name; 7918c2ecf20Sopenharmony_ci enum mlxsw_pci_queue_type type; 7928c2ecf20Sopenharmony_ci void (*pre_init)(struct mlxsw_pci *mlxsw_pci, 7938c2ecf20Sopenharmony_ci struct mlxsw_pci_queue *q); 7948c2ecf20Sopenharmony_ci int (*init)(struct mlxsw_pci *mlxsw_pci, char *mbox, 7958c2ecf20Sopenharmony_ci struct mlxsw_pci_queue *q); 7968c2ecf20Sopenharmony_ci void (*fini)(struct mlxsw_pci *mlxsw_pci, 7978c2ecf20Sopenharmony_ci struct mlxsw_pci_queue *q); 7988c2ecf20Sopenharmony_ci void (*tasklet)(struct tasklet_struct *t); 7998c2ecf20Sopenharmony_ci u16 (*elem_count_f)(const struct mlxsw_pci_queue *q); 8008c2ecf20Sopenharmony_ci u8 (*elem_size_f)(const struct mlxsw_pci_queue *q); 8018c2ecf20Sopenharmony_ci u16 elem_count; 8028c2ecf20Sopenharmony_ci u8 elem_size; 8038c2ecf20Sopenharmony_ci}; 8048c2ecf20Sopenharmony_ci 8058c2ecf20Sopenharmony_cistatic const struct mlxsw_pci_queue_ops mlxsw_pci_sdq_ops = { 8068c2ecf20Sopenharmony_ci .type = MLXSW_PCI_QUEUE_TYPE_SDQ, 8078c2ecf20Sopenharmony_ci .init = mlxsw_pci_sdq_init, 8088c2ecf20Sopenharmony_ci .fini = mlxsw_pci_sdq_fini, 8098c2ecf20Sopenharmony_ci .elem_count = MLXSW_PCI_WQE_COUNT, 8108c2ecf20Sopenharmony_ci .elem_size = MLXSW_PCI_WQE_SIZE, 8118c2ecf20Sopenharmony_ci}; 8128c2ecf20Sopenharmony_ci 8138c2ecf20Sopenharmony_cistatic const struct mlxsw_pci_queue_ops mlxsw_pci_rdq_ops = { 8148c2ecf20Sopenharmony_ci .type = MLXSW_PCI_QUEUE_TYPE_RDQ, 8158c2ecf20Sopenharmony_ci .init = mlxsw_pci_rdq_init, 8168c2ecf20Sopenharmony_ci .fini = mlxsw_pci_rdq_fini, 8178c2ecf20Sopenharmony_ci .elem_count = MLXSW_PCI_WQE_COUNT, 8188c2ecf20Sopenharmony_ci .elem_size = MLXSW_PCI_WQE_SIZE 8198c2ecf20Sopenharmony_ci}; 8208c2ecf20Sopenharmony_ci 8218c2ecf20Sopenharmony_cistatic const struct mlxsw_pci_queue_ops mlxsw_pci_cq_ops = { 8228c2ecf20Sopenharmony_ci .type = MLXSW_PCI_QUEUE_TYPE_CQ, 8238c2ecf20Sopenharmony_ci .pre_init = mlxsw_pci_cq_pre_init, 8248c2ecf20Sopenharmony_ci .init = mlxsw_pci_cq_init, 8258c2ecf20Sopenharmony_ci .fini = mlxsw_pci_cq_fini, 8268c2ecf20Sopenharmony_ci .tasklet = mlxsw_pci_cq_tasklet, 8278c2ecf20Sopenharmony_ci .elem_count_f = mlxsw_pci_cq_elem_count, 8288c2ecf20Sopenharmony_ci .elem_size_f = mlxsw_pci_cq_elem_size 8298c2ecf20Sopenharmony_ci}; 8308c2ecf20Sopenharmony_ci 8318c2ecf20Sopenharmony_cistatic const struct mlxsw_pci_queue_ops mlxsw_pci_eq_ops = { 8328c2ecf20Sopenharmony_ci .type = MLXSW_PCI_QUEUE_TYPE_EQ, 8338c2ecf20Sopenharmony_ci .init = mlxsw_pci_eq_init, 8348c2ecf20Sopenharmony_ci .fini = mlxsw_pci_eq_fini, 8358c2ecf20Sopenharmony_ci .tasklet = mlxsw_pci_eq_tasklet, 8368c2ecf20Sopenharmony_ci .elem_count = MLXSW_PCI_EQE_COUNT, 8378c2ecf20Sopenharmony_ci .elem_size = MLXSW_PCI_EQE_SIZE 8388c2ecf20Sopenharmony_ci}; 8398c2ecf20Sopenharmony_ci 8408c2ecf20Sopenharmony_cistatic int mlxsw_pci_queue_init(struct mlxsw_pci *mlxsw_pci, char *mbox, 8418c2ecf20Sopenharmony_ci const struct mlxsw_pci_queue_ops *q_ops, 8428c2ecf20Sopenharmony_ci struct mlxsw_pci_queue *q, u8 q_num) 8438c2ecf20Sopenharmony_ci{ 8448c2ecf20Sopenharmony_ci struct mlxsw_pci_mem_item *mem_item = &q->mem_item; 8458c2ecf20Sopenharmony_ci int i; 8468c2ecf20Sopenharmony_ci int err; 8478c2ecf20Sopenharmony_ci 8488c2ecf20Sopenharmony_ci q->num = q_num; 8498c2ecf20Sopenharmony_ci if (q_ops->pre_init) 8508c2ecf20Sopenharmony_ci q_ops->pre_init(mlxsw_pci, q); 8518c2ecf20Sopenharmony_ci 8528c2ecf20Sopenharmony_ci spin_lock_init(&q->lock); 8538c2ecf20Sopenharmony_ci q->count = q_ops->elem_count_f ? q_ops->elem_count_f(q) : 8548c2ecf20Sopenharmony_ci q_ops->elem_count; 8558c2ecf20Sopenharmony_ci q->elem_size = q_ops->elem_size_f ? q_ops->elem_size_f(q) : 8568c2ecf20Sopenharmony_ci q_ops->elem_size; 8578c2ecf20Sopenharmony_ci q->type = q_ops->type; 8588c2ecf20Sopenharmony_ci q->pci = mlxsw_pci; 8598c2ecf20Sopenharmony_ci 8608c2ecf20Sopenharmony_ci if (q_ops->tasklet) 8618c2ecf20Sopenharmony_ci tasklet_setup(&q->tasklet, q_ops->tasklet); 8628c2ecf20Sopenharmony_ci 8638c2ecf20Sopenharmony_ci mem_item->size = MLXSW_PCI_AQ_SIZE; 8648c2ecf20Sopenharmony_ci mem_item->buf = pci_alloc_consistent(mlxsw_pci->pdev, 8658c2ecf20Sopenharmony_ci mem_item->size, 8668c2ecf20Sopenharmony_ci &mem_item->mapaddr); 8678c2ecf20Sopenharmony_ci if (!mem_item->buf) 8688c2ecf20Sopenharmony_ci return -ENOMEM; 8698c2ecf20Sopenharmony_ci 8708c2ecf20Sopenharmony_ci q->elem_info = kcalloc(q->count, sizeof(*q->elem_info), GFP_KERNEL); 8718c2ecf20Sopenharmony_ci if (!q->elem_info) { 8728c2ecf20Sopenharmony_ci err = -ENOMEM; 8738c2ecf20Sopenharmony_ci goto err_elem_info_alloc; 8748c2ecf20Sopenharmony_ci } 8758c2ecf20Sopenharmony_ci 8768c2ecf20Sopenharmony_ci /* Initialize dma mapped elements info elem_info for 8778c2ecf20Sopenharmony_ci * future easy access. 8788c2ecf20Sopenharmony_ci */ 8798c2ecf20Sopenharmony_ci for (i = 0; i < q->count; i++) { 8808c2ecf20Sopenharmony_ci struct mlxsw_pci_queue_elem_info *elem_info; 8818c2ecf20Sopenharmony_ci 8828c2ecf20Sopenharmony_ci elem_info = mlxsw_pci_queue_elem_info_get(q, i); 8838c2ecf20Sopenharmony_ci elem_info->elem = 8848c2ecf20Sopenharmony_ci __mlxsw_pci_queue_elem_get(q, q->elem_size, i); 8858c2ecf20Sopenharmony_ci } 8868c2ecf20Sopenharmony_ci 8878c2ecf20Sopenharmony_ci mlxsw_cmd_mbox_zero(mbox); 8888c2ecf20Sopenharmony_ci err = q_ops->init(mlxsw_pci, mbox, q); 8898c2ecf20Sopenharmony_ci if (err) 8908c2ecf20Sopenharmony_ci goto err_q_ops_init; 8918c2ecf20Sopenharmony_ci return 0; 8928c2ecf20Sopenharmony_ci 8938c2ecf20Sopenharmony_cierr_q_ops_init: 8948c2ecf20Sopenharmony_ci kfree(q->elem_info); 8958c2ecf20Sopenharmony_cierr_elem_info_alloc: 8968c2ecf20Sopenharmony_ci pci_free_consistent(mlxsw_pci->pdev, mem_item->size, 8978c2ecf20Sopenharmony_ci mem_item->buf, mem_item->mapaddr); 8988c2ecf20Sopenharmony_ci return err; 8998c2ecf20Sopenharmony_ci} 9008c2ecf20Sopenharmony_ci 9018c2ecf20Sopenharmony_cistatic void mlxsw_pci_queue_fini(struct mlxsw_pci *mlxsw_pci, 9028c2ecf20Sopenharmony_ci const struct mlxsw_pci_queue_ops *q_ops, 9038c2ecf20Sopenharmony_ci struct mlxsw_pci_queue *q) 9048c2ecf20Sopenharmony_ci{ 9058c2ecf20Sopenharmony_ci struct mlxsw_pci_mem_item *mem_item = &q->mem_item; 9068c2ecf20Sopenharmony_ci 9078c2ecf20Sopenharmony_ci q_ops->fini(mlxsw_pci, q); 9088c2ecf20Sopenharmony_ci kfree(q->elem_info); 9098c2ecf20Sopenharmony_ci pci_free_consistent(mlxsw_pci->pdev, mem_item->size, 9108c2ecf20Sopenharmony_ci mem_item->buf, mem_item->mapaddr); 9118c2ecf20Sopenharmony_ci} 9128c2ecf20Sopenharmony_ci 9138c2ecf20Sopenharmony_cistatic int mlxsw_pci_queue_group_init(struct mlxsw_pci *mlxsw_pci, char *mbox, 9148c2ecf20Sopenharmony_ci const struct mlxsw_pci_queue_ops *q_ops, 9158c2ecf20Sopenharmony_ci u8 num_qs) 9168c2ecf20Sopenharmony_ci{ 9178c2ecf20Sopenharmony_ci struct mlxsw_pci_queue_type_group *queue_group; 9188c2ecf20Sopenharmony_ci int i; 9198c2ecf20Sopenharmony_ci int err; 9208c2ecf20Sopenharmony_ci 9218c2ecf20Sopenharmony_ci queue_group = mlxsw_pci_queue_type_group_get(mlxsw_pci, q_ops->type); 9228c2ecf20Sopenharmony_ci queue_group->q = kcalloc(num_qs, sizeof(*queue_group->q), GFP_KERNEL); 9238c2ecf20Sopenharmony_ci if (!queue_group->q) 9248c2ecf20Sopenharmony_ci return -ENOMEM; 9258c2ecf20Sopenharmony_ci 9268c2ecf20Sopenharmony_ci for (i = 0; i < num_qs; i++) { 9278c2ecf20Sopenharmony_ci err = mlxsw_pci_queue_init(mlxsw_pci, mbox, q_ops, 9288c2ecf20Sopenharmony_ci &queue_group->q[i], i); 9298c2ecf20Sopenharmony_ci if (err) 9308c2ecf20Sopenharmony_ci goto err_queue_init; 9318c2ecf20Sopenharmony_ci } 9328c2ecf20Sopenharmony_ci queue_group->count = num_qs; 9338c2ecf20Sopenharmony_ci 9348c2ecf20Sopenharmony_ci return 0; 9358c2ecf20Sopenharmony_ci 9368c2ecf20Sopenharmony_cierr_queue_init: 9378c2ecf20Sopenharmony_ci for (i--; i >= 0; i--) 9388c2ecf20Sopenharmony_ci mlxsw_pci_queue_fini(mlxsw_pci, q_ops, &queue_group->q[i]); 9398c2ecf20Sopenharmony_ci kfree(queue_group->q); 9408c2ecf20Sopenharmony_ci return err; 9418c2ecf20Sopenharmony_ci} 9428c2ecf20Sopenharmony_ci 9438c2ecf20Sopenharmony_cistatic void mlxsw_pci_queue_group_fini(struct mlxsw_pci *mlxsw_pci, 9448c2ecf20Sopenharmony_ci const struct mlxsw_pci_queue_ops *q_ops) 9458c2ecf20Sopenharmony_ci{ 9468c2ecf20Sopenharmony_ci struct mlxsw_pci_queue_type_group *queue_group; 9478c2ecf20Sopenharmony_ci int i; 9488c2ecf20Sopenharmony_ci 9498c2ecf20Sopenharmony_ci queue_group = mlxsw_pci_queue_type_group_get(mlxsw_pci, q_ops->type); 9508c2ecf20Sopenharmony_ci for (i = 0; i < queue_group->count; i++) 9518c2ecf20Sopenharmony_ci mlxsw_pci_queue_fini(mlxsw_pci, q_ops, &queue_group->q[i]); 9528c2ecf20Sopenharmony_ci kfree(queue_group->q); 9538c2ecf20Sopenharmony_ci} 9548c2ecf20Sopenharmony_ci 9558c2ecf20Sopenharmony_cistatic int mlxsw_pci_aqs_init(struct mlxsw_pci *mlxsw_pci, char *mbox) 9568c2ecf20Sopenharmony_ci{ 9578c2ecf20Sopenharmony_ci struct pci_dev *pdev = mlxsw_pci->pdev; 9588c2ecf20Sopenharmony_ci u8 num_sdqs; 9598c2ecf20Sopenharmony_ci u8 sdq_log2sz; 9608c2ecf20Sopenharmony_ci u8 num_rdqs; 9618c2ecf20Sopenharmony_ci u8 rdq_log2sz; 9628c2ecf20Sopenharmony_ci u8 num_cqs; 9638c2ecf20Sopenharmony_ci u8 cq_log2sz; 9648c2ecf20Sopenharmony_ci u8 cqv2_log2sz; 9658c2ecf20Sopenharmony_ci u8 num_eqs; 9668c2ecf20Sopenharmony_ci u8 eq_log2sz; 9678c2ecf20Sopenharmony_ci int err; 9688c2ecf20Sopenharmony_ci 9698c2ecf20Sopenharmony_ci mlxsw_cmd_mbox_zero(mbox); 9708c2ecf20Sopenharmony_ci err = mlxsw_cmd_query_aq_cap(mlxsw_pci->core, mbox); 9718c2ecf20Sopenharmony_ci if (err) 9728c2ecf20Sopenharmony_ci return err; 9738c2ecf20Sopenharmony_ci 9748c2ecf20Sopenharmony_ci num_sdqs = mlxsw_cmd_mbox_query_aq_cap_max_num_sdqs_get(mbox); 9758c2ecf20Sopenharmony_ci sdq_log2sz = mlxsw_cmd_mbox_query_aq_cap_log_max_sdq_sz_get(mbox); 9768c2ecf20Sopenharmony_ci num_rdqs = mlxsw_cmd_mbox_query_aq_cap_max_num_rdqs_get(mbox); 9778c2ecf20Sopenharmony_ci rdq_log2sz = mlxsw_cmd_mbox_query_aq_cap_log_max_rdq_sz_get(mbox); 9788c2ecf20Sopenharmony_ci num_cqs = mlxsw_cmd_mbox_query_aq_cap_max_num_cqs_get(mbox); 9798c2ecf20Sopenharmony_ci cq_log2sz = mlxsw_cmd_mbox_query_aq_cap_log_max_cq_sz_get(mbox); 9808c2ecf20Sopenharmony_ci cqv2_log2sz = mlxsw_cmd_mbox_query_aq_cap_log_max_cqv2_sz_get(mbox); 9818c2ecf20Sopenharmony_ci num_eqs = mlxsw_cmd_mbox_query_aq_cap_max_num_eqs_get(mbox); 9828c2ecf20Sopenharmony_ci eq_log2sz = mlxsw_cmd_mbox_query_aq_cap_log_max_eq_sz_get(mbox); 9838c2ecf20Sopenharmony_ci 9848c2ecf20Sopenharmony_ci if (num_sdqs + num_rdqs > num_cqs || 9858c2ecf20Sopenharmony_ci num_sdqs < MLXSW_PCI_SDQS_MIN || 9868c2ecf20Sopenharmony_ci num_cqs > MLXSW_PCI_CQS_MAX || num_eqs != MLXSW_PCI_EQS_COUNT) { 9878c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "Unsupported number of queues\n"); 9888c2ecf20Sopenharmony_ci return -EINVAL; 9898c2ecf20Sopenharmony_ci } 9908c2ecf20Sopenharmony_ci 9918c2ecf20Sopenharmony_ci if ((1 << sdq_log2sz != MLXSW_PCI_WQE_COUNT) || 9928c2ecf20Sopenharmony_ci (1 << rdq_log2sz != MLXSW_PCI_WQE_COUNT) || 9938c2ecf20Sopenharmony_ci (1 << cq_log2sz != MLXSW_PCI_CQE01_COUNT) || 9948c2ecf20Sopenharmony_ci (mlxsw_pci->max_cqe_ver == MLXSW_PCI_CQE_V2 && 9958c2ecf20Sopenharmony_ci (1 << cqv2_log2sz != MLXSW_PCI_CQE2_COUNT)) || 9968c2ecf20Sopenharmony_ci (1 << eq_log2sz != MLXSW_PCI_EQE_COUNT)) { 9978c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "Unsupported number of async queue descriptors\n"); 9988c2ecf20Sopenharmony_ci return -EINVAL; 9998c2ecf20Sopenharmony_ci } 10008c2ecf20Sopenharmony_ci 10018c2ecf20Sopenharmony_ci mlxsw_pci->num_sdq_cqs = num_sdqs; 10028c2ecf20Sopenharmony_ci 10038c2ecf20Sopenharmony_ci err = mlxsw_pci_queue_group_init(mlxsw_pci, mbox, &mlxsw_pci_eq_ops, 10048c2ecf20Sopenharmony_ci num_eqs); 10058c2ecf20Sopenharmony_ci if (err) { 10068c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "Failed to initialize event queues\n"); 10078c2ecf20Sopenharmony_ci return err; 10088c2ecf20Sopenharmony_ci } 10098c2ecf20Sopenharmony_ci 10108c2ecf20Sopenharmony_ci err = mlxsw_pci_queue_group_init(mlxsw_pci, mbox, &mlxsw_pci_cq_ops, 10118c2ecf20Sopenharmony_ci num_cqs); 10128c2ecf20Sopenharmony_ci if (err) { 10138c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "Failed to initialize completion queues\n"); 10148c2ecf20Sopenharmony_ci goto err_cqs_init; 10158c2ecf20Sopenharmony_ci } 10168c2ecf20Sopenharmony_ci 10178c2ecf20Sopenharmony_ci err = mlxsw_pci_queue_group_init(mlxsw_pci, mbox, &mlxsw_pci_sdq_ops, 10188c2ecf20Sopenharmony_ci num_sdqs); 10198c2ecf20Sopenharmony_ci if (err) { 10208c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "Failed to initialize send descriptor queues\n"); 10218c2ecf20Sopenharmony_ci goto err_sdqs_init; 10228c2ecf20Sopenharmony_ci } 10238c2ecf20Sopenharmony_ci 10248c2ecf20Sopenharmony_ci err = mlxsw_pci_queue_group_init(mlxsw_pci, mbox, &mlxsw_pci_rdq_ops, 10258c2ecf20Sopenharmony_ci num_rdqs); 10268c2ecf20Sopenharmony_ci if (err) { 10278c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "Failed to initialize receive descriptor queues\n"); 10288c2ecf20Sopenharmony_ci goto err_rdqs_init; 10298c2ecf20Sopenharmony_ci } 10308c2ecf20Sopenharmony_ci 10318c2ecf20Sopenharmony_ci /* We have to poll in command interface until queues are initialized */ 10328c2ecf20Sopenharmony_ci mlxsw_pci->cmd.nopoll = true; 10338c2ecf20Sopenharmony_ci return 0; 10348c2ecf20Sopenharmony_ci 10358c2ecf20Sopenharmony_cierr_rdqs_init: 10368c2ecf20Sopenharmony_ci mlxsw_pci_queue_group_fini(mlxsw_pci, &mlxsw_pci_sdq_ops); 10378c2ecf20Sopenharmony_cierr_sdqs_init: 10388c2ecf20Sopenharmony_ci mlxsw_pci_queue_group_fini(mlxsw_pci, &mlxsw_pci_cq_ops); 10398c2ecf20Sopenharmony_cierr_cqs_init: 10408c2ecf20Sopenharmony_ci mlxsw_pci_queue_group_fini(mlxsw_pci, &mlxsw_pci_eq_ops); 10418c2ecf20Sopenharmony_ci return err; 10428c2ecf20Sopenharmony_ci} 10438c2ecf20Sopenharmony_ci 10448c2ecf20Sopenharmony_cistatic void mlxsw_pci_aqs_fini(struct mlxsw_pci *mlxsw_pci) 10458c2ecf20Sopenharmony_ci{ 10468c2ecf20Sopenharmony_ci mlxsw_pci->cmd.nopoll = false; 10478c2ecf20Sopenharmony_ci mlxsw_pci_queue_group_fini(mlxsw_pci, &mlxsw_pci_rdq_ops); 10488c2ecf20Sopenharmony_ci mlxsw_pci_queue_group_fini(mlxsw_pci, &mlxsw_pci_sdq_ops); 10498c2ecf20Sopenharmony_ci mlxsw_pci_queue_group_fini(mlxsw_pci, &mlxsw_pci_cq_ops); 10508c2ecf20Sopenharmony_ci mlxsw_pci_queue_group_fini(mlxsw_pci, &mlxsw_pci_eq_ops); 10518c2ecf20Sopenharmony_ci} 10528c2ecf20Sopenharmony_ci 10538c2ecf20Sopenharmony_cistatic void 10548c2ecf20Sopenharmony_cimlxsw_pci_config_profile_swid_config(struct mlxsw_pci *mlxsw_pci, 10558c2ecf20Sopenharmony_ci char *mbox, int index, 10568c2ecf20Sopenharmony_ci const struct mlxsw_swid_config *swid) 10578c2ecf20Sopenharmony_ci{ 10588c2ecf20Sopenharmony_ci u8 mask = 0; 10598c2ecf20Sopenharmony_ci 10608c2ecf20Sopenharmony_ci if (swid->used_type) { 10618c2ecf20Sopenharmony_ci mlxsw_cmd_mbox_config_profile_swid_config_type_set( 10628c2ecf20Sopenharmony_ci mbox, index, swid->type); 10638c2ecf20Sopenharmony_ci mask |= 1; 10648c2ecf20Sopenharmony_ci } 10658c2ecf20Sopenharmony_ci if (swid->used_properties) { 10668c2ecf20Sopenharmony_ci mlxsw_cmd_mbox_config_profile_swid_config_properties_set( 10678c2ecf20Sopenharmony_ci mbox, index, swid->properties); 10688c2ecf20Sopenharmony_ci mask |= 2; 10698c2ecf20Sopenharmony_ci } 10708c2ecf20Sopenharmony_ci mlxsw_cmd_mbox_config_profile_swid_config_mask_set(mbox, index, mask); 10718c2ecf20Sopenharmony_ci} 10728c2ecf20Sopenharmony_ci 10738c2ecf20Sopenharmony_cistatic int 10748c2ecf20Sopenharmony_cimlxsw_pci_profile_get_kvd_sizes(const struct mlxsw_pci *mlxsw_pci, 10758c2ecf20Sopenharmony_ci const struct mlxsw_config_profile *profile, 10768c2ecf20Sopenharmony_ci struct mlxsw_res *res) 10778c2ecf20Sopenharmony_ci{ 10788c2ecf20Sopenharmony_ci u64 single_size, double_size, linear_size; 10798c2ecf20Sopenharmony_ci int err; 10808c2ecf20Sopenharmony_ci 10818c2ecf20Sopenharmony_ci err = mlxsw_core_kvd_sizes_get(mlxsw_pci->core, profile, 10828c2ecf20Sopenharmony_ci &single_size, &double_size, 10838c2ecf20Sopenharmony_ci &linear_size); 10848c2ecf20Sopenharmony_ci if (err) 10858c2ecf20Sopenharmony_ci return err; 10868c2ecf20Sopenharmony_ci 10878c2ecf20Sopenharmony_ci MLXSW_RES_SET(res, KVD_SINGLE_SIZE, single_size); 10888c2ecf20Sopenharmony_ci MLXSW_RES_SET(res, KVD_DOUBLE_SIZE, double_size); 10898c2ecf20Sopenharmony_ci MLXSW_RES_SET(res, KVD_LINEAR_SIZE, linear_size); 10908c2ecf20Sopenharmony_ci 10918c2ecf20Sopenharmony_ci return 0; 10928c2ecf20Sopenharmony_ci} 10938c2ecf20Sopenharmony_ci 10948c2ecf20Sopenharmony_cistatic int mlxsw_pci_config_profile(struct mlxsw_pci *mlxsw_pci, char *mbox, 10958c2ecf20Sopenharmony_ci const struct mlxsw_config_profile *profile, 10968c2ecf20Sopenharmony_ci struct mlxsw_res *res) 10978c2ecf20Sopenharmony_ci{ 10988c2ecf20Sopenharmony_ci int i; 10998c2ecf20Sopenharmony_ci int err; 11008c2ecf20Sopenharmony_ci 11018c2ecf20Sopenharmony_ci mlxsw_cmd_mbox_zero(mbox); 11028c2ecf20Sopenharmony_ci 11038c2ecf20Sopenharmony_ci if (profile->used_max_vepa_channels) { 11048c2ecf20Sopenharmony_ci mlxsw_cmd_mbox_config_profile_set_max_vepa_channels_set( 11058c2ecf20Sopenharmony_ci mbox, 1); 11068c2ecf20Sopenharmony_ci mlxsw_cmd_mbox_config_profile_max_vepa_channels_set( 11078c2ecf20Sopenharmony_ci mbox, profile->max_vepa_channels); 11088c2ecf20Sopenharmony_ci } 11098c2ecf20Sopenharmony_ci if (profile->used_max_mid) { 11108c2ecf20Sopenharmony_ci mlxsw_cmd_mbox_config_profile_set_max_mid_set( 11118c2ecf20Sopenharmony_ci mbox, 1); 11128c2ecf20Sopenharmony_ci mlxsw_cmd_mbox_config_profile_max_mid_set( 11138c2ecf20Sopenharmony_ci mbox, profile->max_mid); 11148c2ecf20Sopenharmony_ci } 11158c2ecf20Sopenharmony_ci if (profile->used_max_pgt) { 11168c2ecf20Sopenharmony_ci mlxsw_cmd_mbox_config_profile_set_max_pgt_set( 11178c2ecf20Sopenharmony_ci mbox, 1); 11188c2ecf20Sopenharmony_ci mlxsw_cmd_mbox_config_profile_max_pgt_set( 11198c2ecf20Sopenharmony_ci mbox, profile->max_pgt); 11208c2ecf20Sopenharmony_ci } 11218c2ecf20Sopenharmony_ci if (profile->used_max_system_port) { 11228c2ecf20Sopenharmony_ci mlxsw_cmd_mbox_config_profile_set_max_system_port_set( 11238c2ecf20Sopenharmony_ci mbox, 1); 11248c2ecf20Sopenharmony_ci mlxsw_cmd_mbox_config_profile_max_system_port_set( 11258c2ecf20Sopenharmony_ci mbox, profile->max_system_port); 11268c2ecf20Sopenharmony_ci } 11278c2ecf20Sopenharmony_ci if (profile->used_max_vlan_groups) { 11288c2ecf20Sopenharmony_ci mlxsw_cmd_mbox_config_profile_set_max_vlan_groups_set( 11298c2ecf20Sopenharmony_ci mbox, 1); 11308c2ecf20Sopenharmony_ci mlxsw_cmd_mbox_config_profile_max_vlan_groups_set( 11318c2ecf20Sopenharmony_ci mbox, profile->max_vlan_groups); 11328c2ecf20Sopenharmony_ci } 11338c2ecf20Sopenharmony_ci if (profile->used_max_regions) { 11348c2ecf20Sopenharmony_ci mlxsw_cmd_mbox_config_profile_set_max_regions_set( 11358c2ecf20Sopenharmony_ci mbox, 1); 11368c2ecf20Sopenharmony_ci mlxsw_cmd_mbox_config_profile_max_regions_set( 11378c2ecf20Sopenharmony_ci mbox, profile->max_regions); 11388c2ecf20Sopenharmony_ci } 11398c2ecf20Sopenharmony_ci if (profile->used_flood_tables) { 11408c2ecf20Sopenharmony_ci mlxsw_cmd_mbox_config_profile_set_flood_tables_set( 11418c2ecf20Sopenharmony_ci mbox, 1); 11428c2ecf20Sopenharmony_ci mlxsw_cmd_mbox_config_profile_max_flood_tables_set( 11438c2ecf20Sopenharmony_ci mbox, profile->max_flood_tables); 11448c2ecf20Sopenharmony_ci mlxsw_cmd_mbox_config_profile_max_vid_flood_tables_set( 11458c2ecf20Sopenharmony_ci mbox, profile->max_vid_flood_tables); 11468c2ecf20Sopenharmony_ci mlxsw_cmd_mbox_config_profile_max_fid_offset_flood_tables_set( 11478c2ecf20Sopenharmony_ci mbox, profile->max_fid_offset_flood_tables); 11488c2ecf20Sopenharmony_ci mlxsw_cmd_mbox_config_profile_fid_offset_flood_table_size_set( 11498c2ecf20Sopenharmony_ci mbox, profile->fid_offset_flood_table_size); 11508c2ecf20Sopenharmony_ci mlxsw_cmd_mbox_config_profile_max_fid_flood_tables_set( 11518c2ecf20Sopenharmony_ci mbox, profile->max_fid_flood_tables); 11528c2ecf20Sopenharmony_ci mlxsw_cmd_mbox_config_profile_fid_flood_table_size_set( 11538c2ecf20Sopenharmony_ci mbox, profile->fid_flood_table_size); 11548c2ecf20Sopenharmony_ci } 11558c2ecf20Sopenharmony_ci if (profile->used_flood_mode) { 11568c2ecf20Sopenharmony_ci mlxsw_cmd_mbox_config_profile_set_flood_mode_set( 11578c2ecf20Sopenharmony_ci mbox, 1); 11588c2ecf20Sopenharmony_ci mlxsw_cmd_mbox_config_profile_flood_mode_set( 11598c2ecf20Sopenharmony_ci mbox, profile->flood_mode); 11608c2ecf20Sopenharmony_ci } 11618c2ecf20Sopenharmony_ci if (profile->used_max_ib_mc) { 11628c2ecf20Sopenharmony_ci mlxsw_cmd_mbox_config_profile_set_max_ib_mc_set( 11638c2ecf20Sopenharmony_ci mbox, 1); 11648c2ecf20Sopenharmony_ci mlxsw_cmd_mbox_config_profile_max_ib_mc_set( 11658c2ecf20Sopenharmony_ci mbox, profile->max_ib_mc); 11668c2ecf20Sopenharmony_ci } 11678c2ecf20Sopenharmony_ci if (profile->used_max_pkey) { 11688c2ecf20Sopenharmony_ci mlxsw_cmd_mbox_config_profile_set_max_pkey_set( 11698c2ecf20Sopenharmony_ci mbox, 1); 11708c2ecf20Sopenharmony_ci mlxsw_cmd_mbox_config_profile_max_pkey_set( 11718c2ecf20Sopenharmony_ci mbox, profile->max_pkey); 11728c2ecf20Sopenharmony_ci } 11738c2ecf20Sopenharmony_ci if (profile->used_ar_sec) { 11748c2ecf20Sopenharmony_ci mlxsw_cmd_mbox_config_profile_set_ar_sec_set( 11758c2ecf20Sopenharmony_ci mbox, 1); 11768c2ecf20Sopenharmony_ci mlxsw_cmd_mbox_config_profile_ar_sec_set( 11778c2ecf20Sopenharmony_ci mbox, profile->ar_sec); 11788c2ecf20Sopenharmony_ci } 11798c2ecf20Sopenharmony_ci if (profile->used_adaptive_routing_group_cap) { 11808c2ecf20Sopenharmony_ci mlxsw_cmd_mbox_config_profile_set_adaptive_routing_group_cap_set( 11818c2ecf20Sopenharmony_ci mbox, 1); 11828c2ecf20Sopenharmony_ci mlxsw_cmd_mbox_config_profile_adaptive_routing_group_cap_set( 11838c2ecf20Sopenharmony_ci mbox, profile->adaptive_routing_group_cap); 11848c2ecf20Sopenharmony_ci } 11858c2ecf20Sopenharmony_ci if (profile->used_kvd_sizes && MLXSW_RES_VALID(res, KVD_SIZE)) { 11868c2ecf20Sopenharmony_ci err = mlxsw_pci_profile_get_kvd_sizes(mlxsw_pci, profile, res); 11878c2ecf20Sopenharmony_ci if (err) 11888c2ecf20Sopenharmony_ci return err; 11898c2ecf20Sopenharmony_ci 11908c2ecf20Sopenharmony_ci mlxsw_cmd_mbox_config_profile_set_kvd_linear_size_set(mbox, 1); 11918c2ecf20Sopenharmony_ci mlxsw_cmd_mbox_config_profile_kvd_linear_size_set(mbox, 11928c2ecf20Sopenharmony_ci MLXSW_RES_GET(res, KVD_LINEAR_SIZE)); 11938c2ecf20Sopenharmony_ci mlxsw_cmd_mbox_config_profile_set_kvd_hash_single_size_set(mbox, 11948c2ecf20Sopenharmony_ci 1); 11958c2ecf20Sopenharmony_ci mlxsw_cmd_mbox_config_profile_kvd_hash_single_size_set(mbox, 11968c2ecf20Sopenharmony_ci MLXSW_RES_GET(res, KVD_SINGLE_SIZE)); 11978c2ecf20Sopenharmony_ci mlxsw_cmd_mbox_config_profile_set_kvd_hash_double_size_set( 11988c2ecf20Sopenharmony_ci mbox, 1); 11998c2ecf20Sopenharmony_ci mlxsw_cmd_mbox_config_profile_kvd_hash_double_size_set(mbox, 12008c2ecf20Sopenharmony_ci MLXSW_RES_GET(res, KVD_DOUBLE_SIZE)); 12018c2ecf20Sopenharmony_ci } 12028c2ecf20Sopenharmony_ci 12038c2ecf20Sopenharmony_ci for (i = 0; i < MLXSW_CONFIG_PROFILE_SWID_COUNT; i++) 12048c2ecf20Sopenharmony_ci mlxsw_pci_config_profile_swid_config(mlxsw_pci, mbox, i, 12058c2ecf20Sopenharmony_ci &profile->swid_config[i]); 12068c2ecf20Sopenharmony_ci 12078c2ecf20Sopenharmony_ci if (mlxsw_pci->max_cqe_ver > MLXSW_PCI_CQE_V0) { 12088c2ecf20Sopenharmony_ci mlxsw_cmd_mbox_config_profile_set_cqe_version_set(mbox, 1); 12098c2ecf20Sopenharmony_ci mlxsw_cmd_mbox_config_profile_cqe_version_set(mbox, 1); 12108c2ecf20Sopenharmony_ci } 12118c2ecf20Sopenharmony_ci 12128c2ecf20Sopenharmony_ci return mlxsw_cmd_config_profile_set(mlxsw_pci->core, mbox); 12138c2ecf20Sopenharmony_ci} 12148c2ecf20Sopenharmony_ci 12158c2ecf20Sopenharmony_cistatic int mlxsw_pci_boardinfo(struct mlxsw_pci *mlxsw_pci, char *mbox) 12168c2ecf20Sopenharmony_ci{ 12178c2ecf20Sopenharmony_ci struct mlxsw_bus_info *bus_info = &mlxsw_pci->bus_info; 12188c2ecf20Sopenharmony_ci int err; 12198c2ecf20Sopenharmony_ci 12208c2ecf20Sopenharmony_ci mlxsw_cmd_mbox_zero(mbox); 12218c2ecf20Sopenharmony_ci err = mlxsw_cmd_boardinfo(mlxsw_pci->core, mbox); 12228c2ecf20Sopenharmony_ci if (err) 12238c2ecf20Sopenharmony_ci return err; 12248c2ecf20Sopenharmony_ci mlxsw_cmd_mbox_boardinfo_vsd_memcpy_from(mbox, bus_info->vsd); 12258c2ecf20Sopenharmony_ci mlxsw_cmd_mbox_boardinfo_psid_memcpy_from(mbox, bus_info->psid); 12268c2ecf20Sopenharmony_ci return 0; 12278c2ecf20Sopenharmony_ci} 12288c2ecf20Sopenharmony_ci 12298c2ecf20Sopenharmony_cistatic int mlxsw_pci_fw_area_init(struct mlxsw_pci *mlxsw_pci, char *mbox, 12308c2ecf20Sopenharmony_ci u16 num_pages) 12318c2ecf20Sopenharmony_ci{ 12328c2ecf20Sopenharmony_ci struct mlxsw_pci_mem_item *mem_item; 12338c2ecf20Sopenharmony_ci int nent = 0; 12348c2ecf20Sopenharmony_ci int i; 12358c2ecf20Sopenharmony_ci int err; 12368c2ecf20Sopenharmony_ci 12378c2ecf20Sopenharmony_ci mlxsw_pci->fw_area.items = kcalloc(num_pages, sizeof(*mem_item), 12388c2ecf20Sopenharmony_ci GFP_KERNEL); 12398c2ecf20Sopenharmony_ci if (!mlxsw_pci->fw_area.items) 12408c2ecf20Sopenharmony_ci return -ENOMEM; 12418c2ecf20Sopenharmony_ci mlxsw_pci->fw_area.count = num_pages; 12428c2ecf20Sopenharmony_ci 12438c2ecf20Sopenharmony_ci mlxsw_cmd_mbox_zero(mbox); 12448c2ecf20Sopenharmony_ci for (i = 0; i < num_pages; i++) { 12458c2ecf20Sopenharmony_ci mem_item = &mlxsw_pci->fw_area.items[i]; 12468c2ecf20Sopenharmony_ci 12478c2ecf20Sopenharmony_ci mem_item->size = MLXSW_PCI_PAGE_SIZE; 12488c2ecf20Sopenharmony_ci mem_item->buf = pci_alloc_consistent(mlxsw_pci->pdev, 12498c2ecf20Sopenharmony_ci mem_item->size, 12508c2ecf20Sopenharmony_ci &mem_item->mapaddr); 12518c2ecf20Sopenharmony_ci if (!mem_item->buf) { 12528c2ecf20Sopenharmony_ci err = -ENOMEM; 12538c2ecf20Sopenharmony_ci goto err_alloc; 12548c2ecf20Sopenharmony_ci } 12558c2ecf20Sopenharmony_ci mlxsw_cmd_mbox_map_fa_pa_set(mbox, nent, mem_item->mapaddr); 12568c2ecf20Sopenharmony_ci mlxsw_cmd_mbox_map_fa_log2size_set(mbox, nent, 0); /* 1 page */ 12578c2ecf20Sopenharmony_ci if (++nent == MLXSW_CMD_MAP_FA_VPM_ENTRIES_MAX) { 12588c2ecf20Sopenharmony_ci err = mlxsw_cmd_map_fa(mlxsw_pci->core, mbox, nent); 12598c2ecf20Sopenharmony_ci if (err) 12608c2ecf20Sopenharmony_ci goto err_cmd_map_fa; 12618c2ecf20Sopenharmony_ci nent = 0; 12628c2ecf20Sopenharmony_ci mlxsw_cmd_mbox_zero(mbox); 12638c2ecf20Sopenharmony_ci } 12648c2ecf20Sopenharmony_ci } 12658c2ecf20Sopenharmony_ci 12668c2ecf20Sopenharmony_ci if (nent) { 12678c2ecf20Sopenharmony_ci err = mlxsw_cmd_map_fa(mlxsw_pci->core, mbox, nent); 12688c2ecf20Sopenharmony_ci if (err) 12698c2ecf20Sopenharmony_ci goto err_cmd_map_fa; 12708c2ecf20Sopenharmony_ci } 12718c2ecf20Sopenharmony_ci 12728c2ecf20Sopenharmony_ci return 0; 12738c2ecf20Sopenharmony_ci 12748c2ecf20Sopenharmony_cierr_cmd_map_fa: 12758c2ecf20Sopenharmony_cierr_alloc: 12768c2ecf20Sopenharmony_ci for (i--; i >= 0; i--) { 12778c2ecf20Sopenharmony_ci mem_item = &mlxsw_pci->fw_area.items[i]; 12788c2ecf20Sopenharmony_ci 12798c2ecf20Sopenharmony_ci pci_free_consistent(mlxsw_pci->pdev, mem_item->size, 12808c2ecf20Sopenharmony_ci mem_item->buf, mem_item->mapaddr); 12818c2ecf20Sopenharmony_ci } 12828c2ecf20Sopenharmony_ci kfree(mlxsw_pci->fw_area.items); 12838c2ecf20Sopenharmony_ci return err; 12848c2ecf20Sopenharmony_ci} 12858c2ecf20Sopenharmony_ci 12868c2ecf20Sopenharmony_cistatic void mlxsw_pci_fw_area_fini(struct mlxsw_pci *mlxsw_pci) 12878c2ecf20Sopenharmony_ci{ 12888c2ecf20Sopenharmony_ci struct mlxsw_pci_mem_item *mem_item; 12898c2ecf20Sopenharmony_ci int i; 12908c2ecf20Sopenharmony_ci 12918c2ecf20Sopenharmony_ci mlxsw_cmd_unmap_fa(mlxsw_pci->core); 12928c2ecf20Sopenharmony_ci 12938c2ecf20Sopenharmony_ci for (i = 0; i < mlxsw_pci->fw_area.count; i++) { 12948c2ecf20Sopenharmony_ci mem_item = &mlxsw_pci->fw_area.items[i]; 12958c2ecf20Sopenharmony_ci 12968c2ecf20Sopenharmony_ci pci_free_consistent(mlxsw_pci->pdev, mem_item->size, 12978c2ecf20Sopenharmony_ci mem_item->buf, mem_item->mapaddr); 12988c2ecf20Sopenharmony_ci } 12998c2ecf20Sopenharmony_ci kfree(mlxsw_pci->fw_area.items); 13008c2ecf20Sopenharmony_ci} 13018c2ecf20Sopenharmony_ci 13028c2ecf20Sopenharmony_cistatic irqreturn_t mlxsw_pci_eq_irq_handler(int irq, void *dev_id) 13038c2ecf20Sopenharmony_ci{ 13048c2ecf20Sopenharmony_ci struct mlxsw_pci *mlxsw_pci = dev_id; 13058c2ecf20Sopenharmony_ci struct mlxsw_pci_queue *q; 13068c2ecf20Sopenharmony_ci int i; 13078c2ecf20Sopenharmony_ci 13088c2ecf20Sopenharmony_ci for (i = 0; i < MLXSW_PCI_EQS_COUNT; i++) { 13098c2ecf20Sopenharmony_ci q = mlxsw_pci_eq_get(mlxsw_pci, i); 13108c2ecf20Sopenharmony_ci mlxsw_pci_queue_tasklet_schedule(q); 13118c2ecf20Sopenharmony_ci } 13128c2ecf20Sopenharmony_ci return IRQ_HANDLED; 13138c2ecf20Sopenharmony_ci} 13148c2ecf20Sopenharmony_ci 13158c2ecf20Sopenharmony_cistatic int mlxsw_pci_mbox_alloc(struct mlxsw_pci *mlxsw_pci, 13168c2ecf20Sopenharmony_ci struct mlxsw_pci_mem_item *mbox) 13178c2ecf20Sopenharmony_ci{ 13188c2ecf20Sopenharmony_ci struct pci_dev *pdev = mlxsw_pci->pdev; 13198c2ecf20Sopenharmony_ci int err = 0; 13208c2ecf20Sopenharmony_ci 13218c2ecf20Sopenharmony_ci mbox->size = MLXSW_CMD_MBOX_SIZE; 13228c2ecf20Sopenharmony_ci mbox->buf = pci_alloc_consistent(pdev, MLXSW_CMD_MBOX_SIZE, 13238c2ecf20Sopenharmony_ci &mbox->mapaddr); 13248c2ecf20Sopenharmony_ci if (!mbox->buf) { 13258c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "Failed allocating memory for mailbox\n"); 13268c2ecf20Sopenharmony_ci err = -ENOMEM; 13278c2ecf20Sopenharmony_ci } 13288c2ecf20Sopenharmony_ci 13298c2ecf20Sopenharmony_ci return err; 13308c2ecf20Sopenharmony_ci} 13318c2ecf20Sopenharmony_ci 13328c2ecf20Sopenharmony_cistatic void mlxsw_pci_mbox_free(struct mlxsw_pci *mlxsw_pci, 13338c2ecf20Sopenharmony_ci struct mlxsw_pci_mem_item *mbox) 13348c2ecf20Sopenharmony_ci{ 13358c2ecf20Sopenharmony_ci struct pci_dev *pdev = mlxsw_pci->pdev; 13368c2ecf20Sopenharmony_ci 13378c2ecf20Sopenharmony_ci pci_free_consistent(pdev, MLXSW_CMD_MBOX_SIZE, mbox->buf, 13388c2ecf20Sopenharmony_ci mbox->mapaddr); 13398c2ecf20Sopenharmony_ci} 13408c2ecf20Sopenharmony_ci 13418c2ecf20Sopenharmony_cistatic int mlxsw_pci_sys_ready_wait(struct mlxsw_pci *mlxsw_pci, 13428c2ecf20Sopenharmony_ci const struct pci_device_id *id, 13438c2ecf20Sopenharmony_ci u32 *p_sys_status) 13448c2ecf20Sopenharmony_ci{ 13458c2ecf20Sopenharmony_ci unsigned long end; 13468c2ecf20Sopenharmony_ci u32 val; 13478c2ecf20Sopenharmony_ci 13488c2ecf20Sopenharmony_ci if (id->device == PCI_DEVICE_ID_MELLANOX_SWITCHX2) { 13498c2ecf20Sopenharmony_ci msleep(MLXSW_PCI_SW_RESET_TIMEOUT_MSECS); 13508c2ecf20Sopenharmony_ci return 0; 13518c2ecf20Sopenharmony_ci } 13528c2ecf20Sopenharmony_ci 13538c2ecf20Sopenharmony_ci /* We must wait for the HW to become responsive. */ 13548c2ecf20Sopenharmony_ci msleep(MLXSW_PCI_SW_RESET_WAIT_MSECS); 13558c2ecf20Sopenharmony_ci 13568c2ecf20Sopenharmony_ci end = jiffies + msecs_to_jiffies(MLXSW_PCI_SW_RESET_TIMEOUT_MSECS); 13578c2ecf20Sopenharmony_ci do { 13588c2ecf20Sopenharmony_ci val = mlxsw_pci_read32(mlxsw_pci, FW_READY); 13598c2ecf20Sopenharmony_ci if ((val & MLXSW_PCI_FW_READY_MASK) == MLXSW_PCI_FW_READY_MAGIC) 13608c2ecf20Sopenharmony_ci return 0; 13618c2ecf20Sopenharmony_ci cond_resched(); 13628c2ecf20Sopenharmony_ci } while (time_before(jiffies, end)); 13638c2ecf20Sopenharmony_ci 13648c2ecf20Sopenharmony_ci *p_sys_status = val & MLXSW_PCI_FW_READY_MASK; 13658c2ecf20Sopenharmony_ci 13668c2ecf20Sopenharmony_ci return -EBUSY; 13678c2ecf20Sopenharmony_ci} 13688c2ecf20Sopenharmony_ci 13698c2ecf20Sopenharmony_cistatic int mlxsw_pci_sw_reset(struct mlxsw_pci *mlxsw_pci, 13708c2ecf20Sopenharmony_ci const struct pci_device_id *id) 13718c2ecf20Sopenharmony_ci{ 13728c2ecf20Sopenharmony_ci struct pci_dev *pdev = mlxsw_pci->pdev; 13738c2ecf20Sopenharmony_ci char mrsr_pl[MLXSW_REG_MRSR_LEN]; 13748c2ecf20Sopenharmony_ci u32 sys_status; 13758c2ecf20Sopenharmony_ci int err; 13768c2ecf20Sopenharmony_ci 13778c2ecf20Sopenharmony_ci err = mlxsw_pci_sys_ready_wait(mlxsw_pci, id, &sys_status); 13788c2ecf20Sopenharmony_ci if (err) { 13798c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "Failed to reach system ready status before reset. Status is 0x%x\n", 13808c2ecf20Sopenharmony_ci sys_status); 13818c2ecf20Sopenharmony_ci return err; 13828c2ecf20Sopenharmony_ci } 13838c2ecf20Sopenharmony_ci 13848c2ecf20Sopenharmony_ci mlxsw_reg_mrsr_pack(mrsr_pl); 13858c2ecf20Sopenharmony_ci err = mlxsw_reg_write(mlxsw_pci->core, MLXSW_REG(mrsr), mrsr_pl); 13868c2ecf20Sopenharmony_ci if (err) 13878c2ecf20Sopenharmony_ci return err; 13888c2ecf20Sopenharmony_ci 13898c2ecf20Sopenharmony_ci err = mlxsw_pci_sys_ready_wait(mlxsw_pci, id, &sys_status); 13908c2ecf20Sopenharmony_ci if (err) { 13918c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "Failed to reach system ready status after reset. Status is 0x%x\n", 13928c2ecf20Sopenharmony_ci sys_status); 13938c2ecf20Sopenharmony_ci return err; 13948c2ecf20Sopenharmony_ci } 13958c2ecf20Sopenharmony_ci 13968c2ecf20Sopenharmony_ci return 0; 13978c2ecf20Sopenharmony_ci} 13988c2ecf20Sopenharmony_ci 13998c2ecf20Sopenharmony_cistatic int mlxsw_pci_alloc_irq_vectors(struct mlxsw_pci *mlxsw_pci) 14008c2ecf20Sopenharmony_ci{ 14018c2ecf20Sopenharmony_ci int err; 14028c2ecf20Sopenharmony_ci 14038c2ecf20Sopenharmony_ci err = pci_alloc_irq_vectors(mlxsw_pci->pdev, 1, 1, PCI_IRQ_MSIX); 14048c2ecf20Sopenharmony_ci if (err < 0) 14058c2ecf20Sopenharmony_ci dev_err(&mlxsw_pci->pdev->dev, "MSI-X init failed\n"); 14068c2ecf20Sopenharmony_ci return err; 14078c2ecf20Sopenharmony_ci} 14088c2ecf20Sopenharmony_ci 14098c2ecf20Sopenharmony_cistatic void mlxsw_pci_free_irq_vectors(struct mlxsw_pci *mlxsw_pci) 14108c2ecf20Sopenharmony_ci{ 14118c2ecf20Sopenharmony_ci pci_free_irq_vectors(mlxsw_pci->pdev); 14128c2ecf20Sopenharmony_ci} 14138c2ecf20Sopenharmony_ci 14148c2ecf20Sopenharmony_cistatic int mlxsw_pci_init(void *bus_priv, struct mlxsw_core *mlxsw_core, 14158c2ecf20Sopenharmony_ci const struct mlxsw_config_profile *profile, 14168c2ecf20Sopenharmony_ci struct mlxsw_res *res) 14178c2ecf20Sopenharmony_ci{ 14188c2ecf20Sopenharmony_ci struct mlxsw_pci *mlxsw_pci = bus_priv; 14198c2ecf20Sopenharmony_ci struct pci_dev *pdev = mlxsw_pci->pdev; 14208c2ecf20Sopenharmony_ci char *mbox; 14218c2ecf20Sopenharmony_ci u16 num_pages; 14228c2ecf20Sopenharmony_ci int err; 14238c2ecf20Sopenharmony_ci 14248c2ecf20Sopenharmony_ci mlxsw_pci->core = mlxsw_core; 14258c2ecf20Sopenharmony_ci 14268c2ecf20Sopenharmony_ci mbox = mlxsw_cmd_mbox_alloc(); 14278c2ecf20Sopenharmony_ci if (!mbox) 14288c2ecf20Sopenharmony_ci return -ENOMEM; 14298c2ecf20Sopenharmony_ci 14308c2ecf20Sopenharmony_ci err = mlxsw_pci_sw_reset(mlxsw_pci, mlxsw_pci->id); 14318c2ecf20Sopenharmony_ci if (err) 14328c2ecf20Sopenharmony_ci goto err_sw_reset; 14338c2ecf20Sopenharmony_ci 14348c2ecf20Sopenharmony_ci err = mlxsw_pci_alloc_irq_vectors(mlxsw_pci); 14358c2ecf20Sopenharmony_ci if (err < 0) { 14368c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "MSI-X init failed\n"); 14378c2ecf20Sopenharmony_ci goto err_alloc_irq; 14388c2ecf20Sopenharmony_ci } 14398c2ecf20Sopenharmony_ci 14408c2ecf20Sopenharmony_ci err = mlxsw_cmd_query_fw(mlxsw_core, mbox); 14418c2ecf20Sopenharmony_ci if (err) 14428c2ecf20Sopenharmony_ci goto err_query_fw; 14438c2ecf20Sopenharmony_ci 14448c2ecf20Sopenharmony_ci mlxsw_pci->bus_info.fw_rev.major = 14458c2ecf20Sopenharmony_ci mlxsw_cmd_mbox_query_fw_fw_rev_major_get(mbox); 14468c2ecf20Sopenharmony_ci mlxsw_pci->bus_info.fw_rev.minor = 14478c2ecf20Sopenharmony_ci mlxsw_cmd_mbox_query_fw_fw_rev_minor_get(mbox); 14488c2ecf20Sopenharmony_ci mlxsw_pci->bus_info.fw_rev.subminor = 14498c2ecf20Sopenharmony_ci mlxsw_cmd_mbox_query_fw_fw_rev_subminor_get(mbox); 14508c2ecf20Sopenharmony_ci 14518c2ecf20Sopenharmony_ci if (mlxsw_cmd_mbox_query_fw_cmd_interface_rev_get(mbox) != 1) { 14528c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "Unsupported cmd interface revision ID queried from hw\n"); 14538c2ecf20Sopenharmony_ci err = -EINVAL; 14548c2ecf20Sopenharmony_ci goto err_iface_rev; 14558c2ecf20Sopenharmony_ci } 14568c2ecf20Sopenharmony_ci if (mlxsw_cmd_mbox_query_fw_doorbell_page_bar_get(mbox) != 0) { 14578c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "Unsupported doorbell page bar queried from hw\n"); 14588c2ecf20Sopenharmony_ci err = -EINVAL; 14598c2ecf20Sopenharmony_ci goto err_doorbell_page_bar; 14608c2ecf20Sopenharmony_ci } 14618c2ecf20Sopenharmony_ci 14628c2ecf20Sopenharmony_ci mlxsw_pci->doorbell_offset = 14638c2ecf20Sopenharmony_ci mlxsw_cmd_mbox_query_fw_doorbell_page_offset_get(mbox); 14648c2ecf20Sopenharmony_ci 14658c2ecf20Sopenharmony_ci if (mlxsw_cmd_mbox_query_fw_fr_rn_clk_bar_get(mbox) != 0) { 14668c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "Unsupported free running clock BAR queried from hw\n"); 14678c2ecf20Sopenharmony_ci err = -EINVAL; 14688c2ecf20Sopenharmony_ci goto err_fr_rn_clk_bar; 14698c2ecf20Sopenharmony_ci } 14708c2ecf20Sopenharmony_ci 14718c2ecf20Sopenharmony_ci mlxsw_pci->free_running_clock_offset = 14728c2ecf20Sopenharmony_ci mlxsw_cmd_mbox_query_fw_free_running_clock_offset_get(mbox); 14738c2ecf20Sopenharmony_ci 14748c2ecf20Sopenharmony_ci num_pages = mlxsw_cmd_mbox_query_fw_fw_pages_get(mbox); 14758c2ecf20Sopenharmony_ci err = mlxsw_pci_fw_area_init(mlxsw_pci, mbox, num_pages); 14768c2ecf20Sopenharmony_ci if (err) 14778c2ecf20Sopenharmony_ci goto err_fw_area_init; 14788c2ecf20Sopenharmony_ci 14798c2ecf20Sopenharmony_ci err = mlxsw_pci_boardinfo(mlxsw_pci, mbox); 14808c2ecf20Sopenharmony_ci if (err) 14818c2ecf20Sopenharmony_ci goto err_boardinfo; 14828c2ecf20Sopenharmony_ci 14838c2ecf20Sopenharmony_ci err = mlxsw_core_resources_query(mlxsw_core, mbox, res); 14848c2ecf20Sopenharmony_ci if (err) 14858c2ecf20Sopenharmony_ci goto err_query_resources; 14868c2ecf20Sopenharmony_ci 14878c2ecf20Sopenharmony_ci if (MLXSW_CORE_RES_VALID(mlxsw_core, CQE_V2) && 14888c2ecf20Sopenharmony_ci MLXSW_CORE_RES_GET(mlxsw_core, CQE_V2)) 14898c2ecf20Sopenharmony_ci mlxsw_pci->max_cqe_ver = MLXSW_PCI_CQE_V2; 14908c2ecf20Sopenharmony_ci else if (MLXSW_CORE_RES_VALID(mlxsw_core, CQE_V1) && 14918c2ecf20Sopenharmony_ci MLXSW_CORE_RES_GET(mlxsw_core, CQE_V1)) 14928c2ecf20Sopenharmony_ci mlxsw_pci->max_cqe_ver = MLXSW_PCI_CQE_V1; 14938c2ecf20Sopenharmony_ci else if ((MLXSW_CORE_RES_VALID(mlxsw_core, CQE_V0) && 14948c2ecf20Sopenharmony_ci MLXSW_CORE_RES_GET(mlxsw_core, CQE_V0)) || 14958c2ecf20Sopenharmony_ci !MLXSW_CORE_RES_VALID(mlxsw_core, CQE_V0)) { 14968c2ecf20Sopenharmony_ci mlxsw_pci->max_cqe_ver = MLXSW_PCI_CQE_V0; 14978c2ecf20Sopenharmony_ci } else { 14988c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "Invalid supported CQE version combination reported\n"); 14998c2ecf20Sopenharmony_ci goto err_cqe_v_check; 15008c2ecf20Sopenharmony_ci } 15018c2ecf20Sopenharmony_ci 15028c2ecf20Sopenharmony_ci err = mlxsw_pci_config_profile(mlxsw_pci, mbox, profile, res); 15038c2ecf20Sopenharmony_ci if (err) 15048c2ecf20Sopenharmony_ci goto err_config_profile; 15058c2ecf20Sopenharmony_ci 15068c2ecf20Sopenharmony_ci err = mlxsw_pci_aqs_init(mlxsw_pci, mbox); 15078c2ecf20Sopenharmony_ci if (err) 15088c2ecf20Sopenharmony_ci goto err_aqs_init; 15098c2ecf20Sopenharmony_ci 15108c2ecf20Sopenharmony_ci err = request_irq(pci_irq_vector(pdev, 0), 15118c2ecf20Sopenharmony_ci mlxsw_pci_eq_irq_handler, 0, 15128c2ecf20Sopenharmony_ci mlxsw_pci->bus_info.device_kind, mlxsw_pci); 15138c2ecf20Sopenharmony_ci if (err) { 15148c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "IRQ request failed\n"); 15158c2ecf20Sopenharmony_ci goto err_request_eq_irq; 15168c2ecf20Sopenharmony_ci } 15178c2ecf20Sopenharmony_ci 15188c2ecf20Sopenharmony_ci goto mbox_put; 15198c2ecf20Sopenharmony_ci 15208c2ecf20Sopenharmony_cierr_request_eq_irq: 15218c2ecf20Sopenharmony_ci mlxsw_pci_aqs_fini(mlxsw_pci); 15228c2ecf20Sopenharmony_cierr_aqs_init: 15238c2ecf20Sopenharmony_cierr_config_profile: 15248c2ecf20Sopenharmony_cierr_cqe_v_check: 15258c2ecf20Sopenharmony_cierr_query_resources: 15268c2ecf20Sopenharmony_cierr_boardinfo: 15278c2ecf20Sopenharmony_ci mlxsw_pci_fw_area_fini(mlxsw_pci); 15288c2ecf20Sopenharmony_cierr_fw_area_init: 15298c2ecf20Sopenharmony_cierr_fr_rn_clk_bar: 15308c2ecf20Sopenharmony_cierr_doorbell_page_bar: 15318c2ecf20Sopenharmony_cierr_iface_rev: 15328c2ecf20Sopenharmony_cierr_query_fw: 15338c2ecf20Sopenharmony_ci mlxsw_pci_free_irq_vectors(mlxsw_pci); 15348c2ecf20Sopenharmony_cierr_alloc_irq: 15358c2ecf20Sopenharmony_cierr_sw_reset: 15368c2ecf20Sopenharmony_cimbox_put: 15378c2ecf20Sopenharmony_ci mlxsw_cmd_mbox_free(mbox); 15388c2ecf20Sopenharmony_ci return err; 15398c2ecf20Sopenharmony_ci} 15408c2ecf20Sopenharmony_ci 15418c2ecf20Sopenharmony_cistatic void mlxsw_pci_fini(void *bus_priv) 15428c2ecf20Sopenharmony_ci{ 15438c2ecf20Sopenharmony_ci struct mlxsw_pci *mlxsw_pci = bus_priv; 15448c2ecf20Sopenharmony_ci 15458c2ecf20Sopenharmony_ci free_irq(pci_irq_vector(mlxsw_pci->pdev, 0), mlxsw_pci); 15468c2ecf20Sopenharmony_ci mlxsw_pci_aqs_fini(mlxsw_pci); 15478c2ecf20Sopenharmony_ci mlxsw_pci_fw_area_fini(mlxsw_pci); 15488c2ecf20Sopenharmony_ci mlxsw_pci_free_irq_vectors(mlxsw_pci); 15498c2ecf20Sopenharmony_ci} 15508c2ecf20Sopenharmony_ci 15518c2ecf20Sopenharmony_cistatic struct mlxsw_pci_queue * 15528c2ecf20Sopenharmony_cimlxsw_pci_sdq_pick(struct mlxsw_pci *mlxsw_pci, 15538c2ecf20Sopenharmony_ci const struct mlxsw_tx_info *tx_info) 15548c2ecf20Sopenharmony_ci{ 15558c2ecf20Sopenharmony_ci u8 ctl_sdq_count = mlxsw_pci_sdq_count(mlxsw_pci) - 1; 15568c2ecf20Sopenharmony_ci u8 sdqn; 15578c2ecf20Sopenharmony_ci 15588c2ecf20Sopenharmony_ci if (tx_info->is_emad) { 15598c2ecf20Sopenharmony_ci sdqn = MLXSW_PCI_SDQ_EMAD_INDEX; 15608c2ecf20Sopenharmony_ci } else { 15618c2ecf20Sopenharmony_ci BUILD_BUG_ON(MLXSW_PCI_SDQ_EMAD_INDEX != 0); 15628c2ecf20Sopenharmony_ci sdqn = 1 + (tx_info->local_port % ctl_sdq_count); 15638c2ecf20Sopenharmony_ci } 15648c2ecf20Sopenharmony_ci 15658c2ecf20Sopenharmony_ci return mlxsw_pci_sdq_get(mlxsw_pci, sdqn); 15668c2ecf20Sopenharmony_ci} 15678c2ecf20Sopenharmony_ci 15688c2ecf20Sopenharmony_cistatic bool mlxsw_pci_skb_transmit_busy(void *bus_priv, 15698c2ecf20Sopenharmony_ci const struct mlxsw_tx_info *tx_info) 15708c2ecf20Sopenharmony_ci{ 15718c2ecf20Sopenharmony_ci struct mlxsw_pci *mlxsw_pci = bus_priv; 15728c2ecf20Sopenharmony_ci struct mlxsw_pci_queue *q = mlxsw_pci_sdq_pick(mlxsw_pci, tx_info); 15738c2ecf20Sopenharmony_ci 15748c2ecf20Sopenharmony_ci return !mlxsw_pci_queue_elem_info_producer_get(q); 15758c2ecf20Sopenharmony_ci} 15768c2ecf20Sopenharmony_ci 15778c2ecf20Sopenharmony_cistatic int mlxsw_pci_skb_transmit(void *bus_priv, struct sk_buff *skb, 15788c2ecf20Sopenharmony_ci const struct mlxsw_tx_info *tx_info) 15798c2ecf20Sopenharmony_ci{ 15808c2ecf20Sopenharmony_ci struct mlxsw_pci *mlxsw_pci = bus_priv; 15818c2ecf20Sopenharmony_ci struct mlxsw_pci_queue *q; 15828c2ecf20Sopenharmony_ci struct mlxsw_pci_queue_elem_info *elem_info; 15838c2ecf20Sopenharmony_ci char *wqe; 15848c2ecf20Sopenharmony_ci int i; 15858c2ecf20Sopenharmony_ci int err; 15868c2ecf20Sopenharmony_ci 15878c2ecf20Sopenharmony_ci if (skb_shinfo(skb)->nr_frags > MLXSW_PCI_WQE_SG_ENTRIES - 1) { 15888c2ecf20Sopenharmony_ci err = skb_linearize(skb); 15898c2ecf20Sopenharmony_ci if (err) 15908c2ecf20Sopenharmony_ci return err; 15918c2ecf20Sopenharmony_ci } 15928c2ecf20Sopenharmony_ci 15938c2ecf20Sopenharmony_ci q = mlxsw_pci_sdq_pick(mlxsw_pci, tx_info); 15948c2ecf20Sopenharmony_ci spin_lock_bh(&q->lock); 15958c2ecf20Sopenharmony_ci elem_info = mlxsw_pci_queue_elem_info_producer_get(q); 15968c2ecf20Sopenharmony_ci if (!elem_info) { 15978c2ecf20Sopenharmony_ci /* queue is full */ 15988c2ecf20Sopenharmony_ci err = -EAGAIN; 15998c2ecf20Sopenharmony_ci goto unlock; 16008c2ecf20Sopenharmony_ci } 16018c2ecf20Sopenharmony_ci mlxsw_skb_cb(skb)->tx_info = *tx_info; 16028c2ecf20Sopenharmony_ci elem_info->u.sdq.skb = skb; 16038c2ecf20Sopenharmony_ci 16048c2ecf20Sopenharmony_ci wqe = elem_info->elem; 16058c2ecf20Sopenharmony_ci mlxsw_pci_wqe_c_set(wqe, 1); /* always report completion */ 16068c2ecf20Sopenharmony_ci mlxsw_pci_wqe_lp_set(wqe, 0); 16078c2ecf20Sopenharmony_ci mlxsw_pci_wqe_type_set(wqe, MLXSW_PCI_WQE_TYPE_ETHERNET); 16088c2ecf20Sopenharmony_ci 16098c2ecf20Sopenharmony_ci err = mlxsw_pci_wqe_frag_map(mlxsw_pci, wqe, 0, skb->data, 16108c2ecf20Sopenharmony_ci skb_headlen(skb), DMA_TO_DEVICE); 16118c2ecf20Sopenharmony_ci if (err) 16128c2ecf20Sopenharmony_ci goto unlock; 16138c2ecf20Sopenharmony_ci 16148c2ecf20Sopenharmony_ci for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { 16158c2ecf20Sopenharmony_ci const skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; 16168c2ecf20Sopenharmony_ci 16178c2ecf20Sopenharmony_ci err = mlxsw_pci_wqe_frag_map(mlxsw_pci, wqe, i + 1, 16188c2ecf20Sopenharmony_ci skb_frag_address(frag), 16198c2ecf20Sopenharmony_ci skb_frag_size(frag), 16208c2ecf20Sopenharmony_ci DMA_TO_DEVICE); 16218c2ecf20Sopenharmony_ci if (err) 16228c2ecf20Sopenharmony_ci goto unmap_frags; 16238c2ecf20Sopenharmony_ci } 16248c2ecf20Sopenharmony_ci 16258c2ecf20Sopenharmony_ci if (unlikely(skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP)) 16268c2ecf20Sopenharmony_ci skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS; 16278c2ecf20Sopenharmony_ci 16288c2ecf20Sopenharmony_ci /* Set unused sq entries byte count to zero. */ 16298c2ecf20Sopenharmony_ci for (i++; i < MLXSW_PCI_WQE_SG_ENTRIES; i++) 16308c2ecf20Sopenharmony_ci mlxsw_pci_wqe_byte_count_set(wqe, i, 0); 16318c2ecf20Sopenharmony_ci 16328c2ecf20Sopenharmony_ci /* Everything is set up, ring producer doorbell to get HW going */ 16338c2ecf20Sopenharmony_ci q->producer_counter++; 16348c2ecf20Sopenharmony_ci mlxsw_pci_queue_doorbell_producer_ring(mlxsw_pci, q); 16358c2ecf20Sopenharmony_ci 16368c2ecf20Sopenharmony_ci goto unlock; 16378c2ecf20Sopenharmony_ci 16388c2ecf20Sopenharmony_ciunmap_frags: 16398c2ecf20Sopenharmony_ci for (; i >= 0; i--) 16408c2ecf20Sopenharmony_ci mlxsw_pci_wqe_frag_unmap(mlxsw_pci, wqe, i, DMA_TO_DEVICE); 16418c2ecf20Sopenharmony_ciunlock: 16428c2ecf20Sopenharmony_ci spin_unlock_bh(&q->lock); 16438c2ecf20Sopenharmony_ci return err; 16448c2ecf20Sopenharmony_ci} 16458c2ecf20Sopenharmony_ci 16468c2ecf20Sopenharmony_cistatic int mlxsw_pci_cmd_exec(void *bus_priv, u16 opcode, u8 opcode_mod, 16478c2ecf20Sopenharmony_ci u32 in_mod, bool out_mbox_direct, 16488c2ecf20Sopenharmony_ci char *in_mbox, size_t in_mbox_size, 16498c2ecf20Sopenharmony_ci char *out_mbox, size_t out_mbox_size, 16508c2ecf20Sopenharmony_ci u8 *p_status) 16518c2ecf20Sopenharmony_ci{ 16528c2ecf20Sopenharmony_ci struct mlxsw_pci *mlxsw_pci = bus_priv; 16538c2ecf20Sopenharmony_ci dma_addr_t in_mapaddr = 0, out_mapaddr = 0; 16548c2ecf20Sopenharmony_ci bool evreq = mlxsw_pci->cmd.nopoll; 16558c2ecf20Sopenharmony_ci unsigned long timeout = msecs_to_jiffies(MLXSW_PCI_CIR_TIMEOUT_MSECS); 16568c2ecf20Sopenharmony_ci bool *p_wait_done = &mlxsw_pci->cmd.wait_done; 16578c2ecf20Sopenharmony_ci int err; 16588c2ecf20Sopenharmony_ci 16598c2ecf20Sopenharmony_ci *p_status = MLXSW_CMD_STATUS_OK; 16608c2ecf20Sopenharmony_ci 16618c2ecf20Sopenharmony_ci err = mutex_lock_interruptible(&mlxsw_pci->cmd.lock); 16628c2ecf20Sopenharmony_ci if (err) 16638c2ecf20Sopenharmony_ci return err; 16648c2ecf20Sopenharmony_ci 16658c2ecf20Sopenharmony_ci if (in_mbox) { 16668c2ecf20Sopenharmony_ci memcpy(mlxsw_pci->cmd.in_mbox.buf, in_mbox, in_mbox_size); 16678c2ecf20Sopenharmony_ci in_mapaddr = mlxsw_pci->cmd.in_mbox.mapaddr; 16688c2ecf20Sopenharmony_ci } 16698c2ecf20Sopenharmony_ci mlxsw_pci_write32(mlxsw_pci, CIR_IN_PARAM_HI, upper_32_bits(in_mapaddr)); 16708c2ecf20Sopenharmony_ci mlxsw_pci_write32(mlxsw_pci, CIR_IN_PARAM_LO, lower_32_bits(in_mapaddr)); 16718c2ecf20Sopenharmony_ci 16728c2ecf20Sopenharmony_ci if (out_mbox) 16738c2ecf20Sopenharmony_ci out_mapaddr = mlxsw_pci->cmd.out_mbox.mapaddr; 16748c2ecf20Sopenharmony_ci mlxsw_pci_write32(mlxsw_pci, CIR_OUT_PARAM_HI, upper_32_bits(out_mapaddr)); 16758c2ecf20Sopenharmony_ci mlxsw_pci_write32(mlxsw_pci, CIR_OUT_PARAM_LO, lower_32_bits(out_mapaddr)); 16768c2ecf20Sopenharmony_ci 16778c2ecf20Sopenharmony_ci mlxsw_pci_write32(mlxsw_pci, CIR_IN_MODIFIER, in_mod); 16788c2ecf20Sopenharmony_ci mlxsw_pci_write32(mlxsw_pci, CIR_TOKEN, 0); 16798c2ecf20Sopenharmony_ci 16808c2ecf20Sopenharmony_ci *p_wait_done = false; 16818c2ecf20Sopenharmony_ci 16828c2ecf20Sopenharmony_ci wmb(); /* all needs to be written before we write control register */ 16838c2ecf20Sopenharmony_ci mlxsw_pci_write32(mlxsw_pci, CIR_CTRL, 16848c2ecf20Sopenharmony_ci MLXSW_PCI_CIR_CTRL_GO_BIT | 16858c2ecf20Sopenharmony_ci (evreq ? MLXSW_PCI_CIR_CTRL_EVREQ_BIT : 0) | 16868c2ecf20Sopenharmony_ci (opcode_mod << MLXSW_PCI_CIR_CTRL_OPCODE_MOD_SHIFT) | 16878c2ecf20Sopenharmony_ci opcode); 16888c2ecf20Sopenharmony_ci 16898c2ecf20Sopenharmony_ci if (!evreq) { 16908c2ecf20Sopenharmony_ci unsigned long end; 16918c2ecf20Sopenharmony_ci 16928c2ecf20Sopenharmony_ci end = jiffies + timeout; 16938c2ecf20Sopenharmony_ci do { 16948c2ecf20Sopenharmony_ci u32 ctrl = mlxsw_pci_read32(mlxsw_pci, CIR_CTRL); 16958c2ecf20Sopenharmony_ci 16968c2ecf20Sopenharmony_ci if (!(ctrl & MLXSW_PCI_CIR_CTRL_GO_BIT)) { 16978c2ecf20Sopenharmony_ci *p_wait_done = true; 16988c2ecf20Sopenharmony_ci *p_status = ctrl >> MLXSW_PCI_CIR_CTRL_STATUS_SHIFT; 16998c2ecf20Sopenharmony_ci break; 17008c2ecf20Sopenharmony_ci } 17018c2ecf20Sopenharmony_ci cond_resched(); 17028c2ecf20Sopenharmony_ci } while (time_before(jiffies, end)); 17038c2ecf20Sopenharmony_ci } else { 17048c2ecf20Sopenharmony_ci wait_event_timeout(mlxsw_pci->cmd.wait, *p_wait_done, timeout); 17058c2ecf20Sopenharmony_ci *p_status = mlxsw_pci->cmd.comp.status; 17068c2ecf20Sopenharmony_ci } 17078c2ecf20Sopenharmony_ci 17088c2ecf20Sopenharmony_ci err = 0; 17098c2ecf20Sopenharmony_ci if (*p_wait_done) { 17108c2ecf20Sopenharmony_ci if (*p_status) 17118c2ecf20Sopenharmony_ci err = -EIO; 17128c2ecf20Sopenharmony_ci } else { 17138c2ecf20Sopenharmony_ci err = -ETIMEDOUT; 17148c2ecf20Sopenharmony_ci } 17158c2ecf20Sopenharmony_ci 17168c2ecf20Sopenharmony_ci if (!err && out_mbox && out_mbox_direct) { 17178c2ecf20Sopenharmony_ci /* Some commands don't use output param as address to mailbox 17188c2ecf20Sopenharmony_ci * but they store output directly into registers. In that case, 17198c2ecf20Sopenharmony_ci * copy registers into mbox buffer. 17208c2ecf20Sopenharmony_ci */ 17218c2ecf20Sopenharmony_ci __be32 tmp; 17228c2ecf20Sopenharmony_ci 17238c2ecf20Sopenharmony_ci if (!evreq) { 17248c2ecf20Sopenharmony_ci tmp = cpu_to_be32(mlxsw_pci_read32(mlxsw_pci, 17258c2ecf20Sopenharmony_ci CIR_OUT_PARAM_HI)); 17268c2ecf20Sopenharmony_ci memcpy(out_mbox, &tmp, sizeof(tmp)); 17278c2ecf20Sopenharmony_ci tmp = cpu_to_be32(mlxsw_pci_read32(mlxsw_pci, 17288c2ecf20Sopenharmony_ci CIR_OUT_PARAM_LO)); 17298c2ecf20Sopenharmony_ci memcpy(out_mbox + sizeof(tmp), &tmp, sizeof(tmp)); 17308c2ecf20Sopenharmony_ci } 17318c2ecf20Sopenharmony_ci } else if (!err && out_mbox) { 17328c2ecf20Sopenharmony_ci memcpy(out_mbox, mlxsw_pci->cmd.out_mbox.buf, out_mbox_size); 17338c2ecf20Sopenharmony_ci } 17348c2ecf20Sopenharmony_ci 17358c2ecf20Sopenharmony_ci mutex_unlock(&mlxsw_pci->cmd.lock); 17368c2ecf20Sopenharmony_ci 17378c2ecf20Sopenharmony_ci return err; 17388c2ecf20Sopenharmony_ci} 17398c2ecf20Sopenharmony_ci 17408c2ecf20Sopenharmony_cistatic u32 mlxsw_pci_read_frc_h(void *bus_priv) 17418c2ecf20Sopenharmony_ci{ 17428c2ecf20Sopenharmony_ci struct mlxsw_pci *mlxsw_pci = bus_priv; 17438c2ecf20Sopenharmony_ci u64 frc_offset; 17448c2ecf20Sopenharmony_ci 17458c2ecf20Sopenharmony_ci frc_offset = mlxsw_pci->free_running_clock_offset; 17468c2ecf20Sopenharmony_ci return mlxsw_pci_read32(mlxsw_pci, FREE_RUNNING_CLOCK_H(frc_offset)); 17478c2ecf20Sopenharmony_ci} 17488c2ecf20Sopenharmony_ci 17498c2ecf20Sopenharmony_cistatic u32 mlxsw_pci_read_frc_l(void *bus_priv) 17508c2ecf20Sopenharmony_ci{ 17518c2ecf20Sopenharmony_ci struct mlxsw_pci *mlxsw_pci = bus_priv; 17528c2ecf20Sopenharmony_ci u64 frc_offset; 17538c2ecf20Sopenharmony_ci 17548c2ecf20Sopenharmony_ci frc_offset = mlxsw_pci->free_running_clock_offset; 17558c2ecf20Sopenharmony_ci return mlxsw_pci_read32(mlxsw_pci, FREE_RUNNING_CLOCK_L(frc_offset)); 17568c2ecf20Sopenharmony_ci} 17578c2ecf20Sopenharmony_ci 17588c2ecf20Sopenharmony_cistatic const struct mlxsw_bus mlxsw_pci_bus = { 17598c2ecf20Sopenharmony_ci .kind = "pci", 17608c2ecf20Sopenharmony_ci .init = mlxsw_pci_init, 17618c2ecf20Sopenharmony_ci .fini = mlxsw_pci_fini, 17628c2ecf20Sopenharmony_ci .skb_transmit_busy = mlxsw_pci_skb_transmit_busy, 17638c2ecf20Sopenharmony_ci .skb_transmit = mlxsw_pci_skb_transmit, 17648c2ecf20Sopenharmony_ci .cmd_exec = mlxsw_pci_cmd_exec, 17658c2ecf20Sopenharmony_ci .read_frc_h = mlxsw_pci_read_frc_h, 17668c2ecf20Sopenharmony_ci .read_frc_l = mlxsw_pci_read_frc_l, 17678c2ecf20Sopenharmony_ci .features = MLXSW_BUS_F_TXRX | MLXSW_BUS_F_RESET, 17688c2ecf20Sopenharmony_ci}; 17698c2ecf20Sopenharmony_ci 17708c2ecf20Sopenharmony_cistatic int mlxsw_pci_cmd_init(struct mlxsw_pci *mlxsw_pci) 17718c2ecf20Sopenharmony_ci{ 17728c2ecf20Sopenharmony_ci int err; 17738c2ecf20Sopenharmony_ci 17748c2ecf20Sopenharmony_ci mutex_init(&mlxsw_pci->cmd.lock); 17758c2ecf20Sopenharmony_ci init_waitqueue_head(&mlxsw_pci->cmd.wait); 17768c2ecf20Sopenharmony_ci 17778c2ecf20Sopenharmony_ci err = mlxsw_pci_mbox_alloc(mlxsw_pci, &mlxsw_pci->cmd.in_mbox); 17788c2ecf20Sopenharmony_ci if (err) 17798c2ecf20Sopenharmony_ci goto err_in_mbox_alloc; 17808c2ecf20Sopenharmony_ci 17818c2ecf20Sopenharmony_ci err = mlxsw_pci_mbox_alloc(mlxsw_pci, &mlxsw_pci->cmd.out_mbox); 17828c2ecf20Sopenharmony_ci if (err) 17838c2ecf20Sopenharmony_ci goto err_out_mbox_alloc; 17848c2ecf20Sopenharmony_ci 17858c2ecf20Sopenharmony_ci return 0; 17868c2ecf20Sopenharmony_ci 17878c2ecf20Sopenharmony_cierr_out_mbox_alloc: 17888c2ecf20Sopenharmony_ci mlxsw_pci_mbox_free(mlxsw_pci, &mlxsw_pci->cmd.in_mbox); 17898c2ecf20Sopenharmony_cierr_in_mbox_alloc: 17908c2ecf20Sopenharmony_ci mutex_destroy(&mlxsw_pci->cmd.lock); 17918c2ecf20Sopenharmony_ci return err; 17928c2ecf20Sopenharmony_ci} 17938c2ecf20Sopenharmony_ci 17948c2ecf20Sopenharmony_cistatic void mlxsw_pci_cmd_fini(struct mlxsw_pci *mlxsw_pci) 17958c2ecf20Sopenharmony_ci{ 17968c2ecf20Sopenharmony_ci mlxsw_pci_mbox_free(mlxsw_pci, &mlxsw_pci->cmd.out_mbox); 17978c2ecf20Sopenharmony_ci mlxsw_pci_mbox_free(mlxsw_pci, &mlxsw_pci->cmd.in_mbox); 17988c2ecf20Sopenharmony_ci mutex_destroy(&mlxsw_pci->cmd.lock); 17998c2ecf20Sopenharmony_ci} 18008c2ecf20Sopenharmony_ci 18018c2ecf20Sopenharmony_cistatic int mlxsw_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) 18028c2ecf20Sopenharmony_ci{ 18038c2ecf20Sopenharmony_ci const char *driver_name = pdev->driver->name; 18048c2ecf20Sopenharmony_ci struct mlxsw_pci *mlxsw_pci; 18058c2ecf20Sopenharmony_ci int err; 18068c2ecf20Sopenharmony_ci 18078c2ecf20Sopenharmony_ci mlxsw_pci = kzalloc(sizeof(*mlxsw_pci), GFP_KERNEL); 18088c2ecf20Sopenharmony_ci if (!mlxsw_pci) 18098c2ecf20Sopenharmony_ci return -ENOMEM; 18108c2ecf20Sopenharmony_ci 18118c2ecf20Sopenharmony_ci err = pci_enable_device(pdev); 18128c2ecf20Sopenharmony_ci if (err) { 18138c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "pci_enable_device failed\n"); 18148c2ecf20Sopenharmony_ci goto err_pci_enable_device; 18158c2ecf20Sopenharmony_ci } 18168c2ecf20Sopenharmony_ci 18178c2ecf20Sopenharmony_ci err = pci_request_regions(pdev, driver_name); 18188c2ecf20Sopenharmony_ci if (err) { 18198c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "pci_request_regions failed\n"); 18208c2ecf20Sopenharmony_ci goto err_pci_request_regions; 18218c2ecf20Sopenharmony_ci } 18228c2ecf20Sopenharmony_ci 18238c2ecf20Sopenharmony_ci err = pci_set_dma_mask(pdev, DMA_BIT_MASK(64)); 18248c2ecf20Sopenharmony_ci if (!err) { 18258c2ecf20Sopenharmony_ci err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64)); 18268c2ecf20Sopenharmony_ci if (err) { 18278c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "pci_set_consistent_dma_mask failed\n"); 18288c2ecf20Sopenharmony_ci goto err_pci_set_dma_mask; 18298c2ecf20Sopenharmony_ci } 18308c2ecf20Sopenharmony_ci } else { 18318c2ecf20Sopenharmony_ci err = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); 18328c2ecf20Sopenharmony_ci if (err) { 18338c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "pci_set_dma_mask failed\n"); 18348c2ecf20Sopenharmony_ci goto err_pci_set_dma_mask; 18358c2ecf20Sopenharmony_ci } 18368c2ecf20Sopenharmony_ci } 18378c2ecf20Sopenharmony_ci 18388c2ecf20Sopenharmony_ci if (pci_resource_len(pdev, 0) < MLXSW_PCI_BAR0_SIZE) { 18398c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "invalid PCI region size\n"); 18408c2ecf20Sopenharmony_ci err = -EINVAL; 18418c2ecf20Sopenharmony_ci goto err_pci_resource_len_check; 18428c2ecf20Sopenharmony_ci } 18438c2ecf20Sopenharmony_ci 18448c2ecf20Sopenharmony_ci mlxsw_pci->hw_addr = ioremap(pci_resource_start(pdev, 0), 18458c2ecf20Sopenharmony_ci pci_resource_len(pdev, 0)); 18468c2ecf20Sopenharmony_ci if (!mlxsw_pci->hw_addr) { 18478c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "ioremap failed\n"); 18488c2ecf20Sopenharmony_ci err = -EIO; 18498c2ecf20Sopenharmony_ci goto err_ioremap; 18508c2ecf20Sopenharmony_ci } 18518c2ecf20Sopenharmony_ci pci_set_master(pdev); 18528c2ecf20Sopenharmony_ci 18538c2ecf20Sopenharmony_ci mlxsw_pci->pdev = pdev; 18548c2ecf20Sopenharmony_ci pci_set_drvdata(pdev, mlxsw_pci); 18558c2ecf20Sopenharmony_ci 18568c2ecf20Sopenharmony_ci err = mlxsw_pci_cmd_init(mlxsw_pci); 18578c2ecf20Sopenharmony_ci if (err) 18588c2ecf20Sopenharmony_ci goto err_pci_cmd_init; 18598c2ecf20Sopenharmony_ci 18608c2ecf20Sopenharmony_ci mlxsw_pci->bus_info.device_kind = driver_name; 18618c2ecf20Sopenharmony_ci mlxsw_pci->bus_info.device_name = pci_name(mlxsw_pci->pdev); 18628c2ecf20Sopenharmony_ci mlxsw_pci->bus_info.dev = &pdev->dev; 18638c2ecf20Sopenharmony_ci mlxsw_pci->bus_info.read_frc_capable = true; 18648c2ecf20Sopenharmony_ci mlxsw_pci->id = id; 18658c2ecf20Sopenharmony_ci 18668c2ecf20Sopenharmony_ci err = mlxsw_core_bus_device_register(&mlxsw_pci->bus_info, 18678c2ecf20Sopenharmony_ci &mlxsw_pci_bus, mlxsw_pci, false, 18688c2ecf20Sopenharmony_ci NULL, NULL); 18698c2ecf20Sopenharmony_ci if (err) { 18708c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "cannot register bus device\n"); 18718c2ecf20Sopenharmony_ci goto err_bus_device_register; 18728c2ecf20Sopenharmony_ci } 18738c2ecf20Sopenharmony_ci 18748c2ecf20Sopenharmony_ci return 0; 18758c2ecf20Sopenharmony_ci 18768c2ecf20Sopenharmony_cierr_bus_device_register: 18778c2ecf20Sopenharmony_ci mlxsw_pci_cmd_fini(mlxsw_pci); 18788c2ecf20Sopenharmony_cierr_pci_cmd_init: 18798c2ecf20Sopenharmony_ci iounmap(mlxsw_pci->hw_addr); 18808c2ecf20Sopenharmony_cierr_ioremap: 18818c2ecf20Sopenharmony_cierr_pci_resource_len_check: 18828c2ecf20Sopenharmony_cierr_pci_set_dma_mask: 18838c2ecf20Sopenharmony_ci pci_release_regions(pdev); 18848c2ecf20Sopenharmony_cierr_pci_request_regions: 18858c2ecf20Sopenharmony_ci pci_disable_device(pdev); 18868c2ecf20Sopenharmony_cierr_pci_enable_device: 18878c2ecf20Sopenharmony_ci kfree(mlxsw_pci); 18888c2ecf20Sopenharmony_ci return err; 18898c2ecf20Sopenharmony_ci} 18908c2ecf20Sopenharmony_ci 18918c2ecf20Sopenharmony_cistatic void mlxsw_pci_remove(struct pci_dev *pdev) 18928c2ecf20Sopenharmony_ci{ 18938c2ecf20Sopenharmony_ci struct mlxsw_pci *mlxsw_pci = pci_get_drvdata(pdev); 18948c2ecf20Sopenharmony_ci 18958c2ecf20Sopenharmony_ci mlxsw_core_bus_device_unregister(mlxsw_pci->core, false); 18968c2ecf20Sopenharmony_ci mlxsw_pci_cmd_fini(mlxsw_pci); 18978c2ecf20Sopenharmony_ci iounmap(mlxsw_pci->hw_addr); 18988c2ecf20Sopenharmony_ci pci_release_regions(mlxsw_pci->pdev); 18998c2ecf20Sopenharmony_ci pci_disable_device(mlxsw_pci->pdev); 19008c2ecf20Sopenharmony_ci kfree(mlxsw_pci); 19018c2ecf20Sopenharmony_ci} 19028c2ecf20Sopenharmony_ci 19038c2ecf20Sopenharmony_ciint mlxsw_pci_driver_register(struct pci_driver *pci_driver) 19048c2ecf20Sopenharmony_ci{ 19058c2ecf20Sopenharmony_ci pci_driver->probe = mlxsw_pci_probe; 19068c2ecf20Sopenharmony_ci pci_driver->remove = mlxsw_pci_remove; 19078c2ecf20Sopenharmony_ci pci_driver->shutdown = mlxsw_pci_remove; 19088c2ecf20Sopenharmony_ci return pci_register_driver(pci_driver); 19098c2ecf20Sopenharmony_ci} 19108c2ecf20Sopenharmony_ciEXPORT_SYMBOL(mlxsw_pci_driver_register); 19118c2ecf20Sopenharmony_ci 19128c2ecf20Sopenharmony_civoid mlxsw_pci_driver_unregister(struct pci_driver *pci_driver) 19138c2ecf20Sopenharmony_ci{ 19148c2ecf20Sopenharmony_ci pci_unregister_driver(pci_driver); 19158c2ecf20Sopenharmony_ci} 19168c2ecf20Sopenharmony_ciEXPORT_SYMBOL(mlxsw_pci_driver_unregister); 19178c2ecf20Sopenharmony_ci 19188c2ecf20Sopenharmony_cistatic int __init mlxsw_pci_module_init(void) 19198c2ecf20Sopenharmony_ci{ 19208c2ecf20Sopenharmony_ci return 0; 19218c2ecf20Sopenharmony_ci} 19228c2ecf20Sopenharmony_ci 19238c2ecf20Sopenharmony_cistatic void __exit mlxsw_pci_module_exit(void) 19248c2ecf20Sopenharmony_ci{ 19258c2ecf20Sopenharmony_ci} 19268c2ecf20Sopenharmony_ci 19278c2ecf20Sopenharmony_cimodule_init(mlxsw_pci_module_init); 19288c2ecf20Sopenharmony_cimodule_exit(mlxsw_pci_module_exit); 19298c2ecf20Sopenharmony_ci 19308c2ecf20Sopenharmony_ciMODULE_LICENSE("Dual BSD/GPL"); 19318c2ecf20Sopenharmony_ciMODULE_AUTHOR("Jiri Pirko <jiri@mellanox.com>"); 19328c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Mellanox switch PCI interface driver"); 1933