162306a36Sopenharmony_ci// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 262306a36Sopenharmony_ci/* Copyright (c) 2015-2018 Mellanox Technologies. All rights reserved */ 362306a36Sopenharmony_ci 462306a36Sopenharmony_ci#include <linux/kernel.h> 562306a36Sopenharmony_ci#include <linux/module.h> 662306a36Sopenharmony_ci#include <linux/export.h> 762306a36Sopenharmony_ci#include <linux/err.h> 862306a36Sopenharmony_ci#include <linux/device.h> 962306a36Sopenharmony_ci#include <linux/pci.h> 1062306a36Sopenharmony_ci#include <linux/interrupt.h> 1162306a36Sopenharmony_ci#include <linux/wait.h> 1262306a36Sopenharmony_ci#include <linux/types.h> 1362306a36Sopenharmony_ci#include <linux/skbuff.h> 1462306a36Sopenharmony_ci#include <linux/if_vlan.h> 1562306a36Sopenharmony_ci#include <linux/log2.h> 1662306a36Sopenharmony_ci#include <linux/string.h> 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_ci#include "pci_hw.h" 1962306a36Sopenharmony_ci#include "pci.h" 2062306a36Sopenharmony_ci#include "core.h" 2162306a36Sopenharmony_ci#include "cmd.h" 2262306a36Sopenharmony_ci#include "port.h" 2362306a36Sopenharmony_ci#include "resources.h" 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_ci#define mlxsw_pci_write32(mlxsw_pci, reg, val) \ 2662306a36Sopenharmony_ci iowrite32be(val, (mlxsw_pci)->hw_addr + (MLXSW_PCI_ ## reg)) 2762306a36Sopenharmony_ci#define mlxsw_pci_read32(mlxsw_pci, reg) \ 2862306a36Sopenharmony_ci ioread32be((mlxsw_pci)->hw_addr + (MLXSW_PCI_ ## reg)) 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_cienum mlxsw_pci_queue_type { 3162306a36Sopenharmony_ci MLXSW_PCI_QUEUE_TYPE_SDQ, 3262306a36Sopenharmony_ci MLXSW_PCI_QUEUE_TYPE_RDQ, 3362306a36Sopenharmony_ci MLXSW_PCI_QUEUE_TYPE_CQ, 3462306a36Sopenharmony_ci MLXSW_PCI_QUEUE_TYPE_EQ, 3562306a36Sopenharmony_ci}; 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_ci#define MLXSW_PCI_QUEUE_TYPE_COUNT 4 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_cistatic const u16 mlxsw_pci_doorbell_type_offset[] = { 4062306a36Sopenharmony_ci MLXSW_PCI_DOORBELL_SDQ_OFFSET, /* for type MLXSW_PCI_QUEUE_TYPE_SDQ */ 4162306a36Sopenharmony_ci MLXSW_PCI_DOORBELL_RDQ_OFFSET, /* for type MLXSW_PCI_QUEUE_TYPE_RDQ */ 4262306a36Sopenharmony_ci MLXSW_PCI_DOORBELL_CQ_OFFSET, /* for type MLXSW_PCI_QUEUE_TYPE_CQ */ 4362306a36Sopenharmony_ci MLXSW_PCI_DOORBELL_EQ_OFFSET, /* for type MLXSW_PCI_QUEUE_TYPE_EQ */ 4462306a36Sopenharmony_ci}; 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_cistatic const u16 mlxsw_pci_doorbell_arm_type_offset[] = { 4762306a36Sopenharmony_ci 0, /* unused */ 4862306a36Sopenharmony_ci 0, /* unused */ 4962306a36Sopenharmony_ci MLXSW_PCI_DOORBELL_ARM_CQ_OFFSET, /* for type MLXSW_PCI_QUEUE_TYPE_CQ */ 5062306a36Sopenharmony_ci MLXSW_PCI_DOORBELL_ARM_EQ_OFFSET, /* for type MLXSW_PCI_QUEUE_TYPE_EQ */ 5162306a36Sopenharmony_ci}; 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_cistruct mlxsw_pci_mem_item { 5462306a36Sopenharmony_ci char *buf; 5562306a36Sopenharmony_ci dma_addr_t mapaddr; 5662306a36Sopenharmony_ci size_t size; 5762306a36Sopenharmony_ci}; 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_cistruct mlxsw_pci_queue_elem_info { 6062306a36Sopenharmony_ci char *elem; /* pointer to actual dma mapped element mem chunk */ 6162306a36Sopenharmony_ci union { 6262306a36Sopenharmony_ci struct { 6362306a36Sopenharmony_ci struct sk_buff *skb; 6462306a36Sopenharmony_ci } sdq; 6562306a36Sopenharmony_ci struct { 6662306a36Sopenharmony_ci struct sk_buff *skb; 6762306a36Sopenharmony_ci } rdq; 6862306a36Sopenharmony_ci } u; 6962306a36Sopenharmony_ci}; 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_cistruct mlxsw_pci_queue { 7262306a36Sopenharmony_ci spinlock_t lock; /* for queue accesses */ 7362306a36Sopenharmony_ci struct mlxsw_pci_mem_item mem_item; 7462306a36Sopenharmony_ci struct mlxsw_pci_queue_elem_info *elem_info; 7562306a36Sopenharmony_ci u16 producer_counter; 7662306a36Sopenharmony_ci u16 consumer_counter; 7762306a36Sopenharmony_ci u16 count; /* number of elements in queue */ 7862306a36Sopenharmony_ci u8 num; /* queue number */ 7962306a36Sopenharmony_ci u8 elem_size; /* size of one element */ 8062306a36Sopenharmony_ci enum mlxsw_pci_queue_type type; 8162306a36Sopenharmony_ci struct tasklet_struct tasklet; /* queue processing tasklet */ 8262306a36Sopenharmony_ci struct mlxsw_pci *pci; 8362306a36Sopenharmony_ci union { 8462306a36Sopenharmony_ci struct { 8562306a36Sopenharmony_ci u32 comp_sdq_count; 8662306a36Sopenharmony_ci u32 comp_rdq_count; 8762306a36Sopenharmony_ci enum mlxsw_pci_cqe_v v; 8862306a36Sopenharmony_ci } cq; 8962306a36Sopenharmony_ci struct { 9062306a36Sopenharmony_ci u32 ev_cmd_count; 9162306a36Sopenharmony_ci u32 ev_comp_count; 9262306a36Sopenharmony_ci u32 ev_other_count; 9362306a36Sopenharmony_ci } eq; 9462306a36Sopenharmony_ci } u; 9562306a36Sopenharmony_ci}; 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_cistruct mlxsw_pci_queue_type_group { 9862306a36Sopenharmony_ci struct mlxsw_pci_queue *q; 9962306a36Sopenharmony_ci u8 count; /* number of queues in group */ 10062306a36Sopenharmony_ci}; 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_cistruct mlxsw_pci { 10362306a36Sopenharmony_ci struct pci_dev *pdev; 10462306a36Sopenharmony_ci u8 __iomem *hw_addr; 10562306a36Sopenharmony_ci u64 free_running_clock_offset; 10662306a36Sopenharmony_ci u64 utc_sec_offset; 10762306a36Sopenharmony_ci u64 utc_nsec_offset; 10862306a36Sopenharmony_ci struct mlxsw_pci_queue_type_group queues[MLXSW_PCI_QUEUE_TYPE_COUNT]; 10962306a36Sopenharmony_ci u32 doorbell_offset; 11062306a36Sopenharmony_ci struct mlxsw_core *core; 11162306a36Sopenharmony_ci struct { 11262306a36Sopenharmony_ci struct mlxsw_pci_mem_item *items; 11362306a36Sopenharmony_ci unsigned int count; 11462306a36Sopenharmony_ci } fw_area; 11562306a36Sopenharmony_ci struct { 11662306a36Sopenharmony_ci struct mlxsw_pci_mem_item out_mbox; 11762306a36Sopenharmony_ci struct mlxsw_pci_mem_item in_mbox; 11862306a36Sopenharmony_ci struct mutex lock; /* Lock access to command registers */ 11962306a36Sopenharmony_ci bool nopoll; 12062306a36Sopenharmony_ci wait_queue_head_t wait; 12162306a36Sopenharmony_ci bool wait_done; 12262306a36Sopenharmony_ci struct { 12362306a36Sopenharmony_ci u8 status; 12462306a36Sopenharmony_ci u64 out_param; 12562306a36Sopenharmony_ci } comp; 12662306a36Sopenharmony_ci } cmd; 12762306a36Sopenharmony_ci struct mlxsw_bus_info bus_info; 12862306a36Sopenharmony_ci const struct pci_device_id *id; 12962306a36Sopenharmony_ci enum mlxsw_pci_cqe_v max_cqe_ver; /* Maximal supported CQE version */ 13062306a36Sopenharmony_ci u8 num_sdq_cqs; /* Number of CQs used for SDQs */ 13162306a36Sopenharmony_ci}; 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_cistatic void mlxsw_pci_queue_tasklet_schedule(struct mlxsw_pci_queue *q) 13462306a36Sopenharmony_ci{ 13562306a36Sopenharmony_ci tasklet_schedule(&q->tasklet); 13662306a36Sopenharmony_ci} 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_cistatic char *__mlxsw_pci_queue_elem_get(struct mlxsw_pci_queue *q, 13962306a36Sopenharmony_ci size_t elem_size, int elem_index) 14062306a36Sopenharmony_ci{ 14162306a36Sopenharmony_ci return q->mem_item.buf + (elem_size * elem_index); 14262306a36Sopenharmony_ci} 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_cistatic struct mlxsw_pci_queue_elem_info * 14562306a36Sopenharmony_cimlxsw_pci_queue_elem_info_get(struct mlxsw_pci_queue *q, int elem_index) 14662306a36Sopenharmony_ci{ 14762306a36Sopenharmony_ci return &q->elem_info[elem_index]; 14862306a36Sopenharmony_ci} 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_cistatic struct mlxsw_pci_queue_elem_info * 15162306a36Sopenharmony_cimlxsw_pci_queue_elem_info_producer_get(struct mlxsw_pci_queue *q) 15262306a36Sopenharmony_ci{ 15362306a36Sopenharmony_ci int index = q->producer_counter & (q->count - 1); 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_ci if ((u16) (q->producer_counter - q->consumer_counter) == q->count) 15662306a36Sopenharmony_ci return NULL; 15762306a36Sopenharmony_ci return mlxsw_pci_queue_elem_info_get(q, index); 15862306a36Sopenharmony_ci} 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_cistatic struct mlxsw_pci_queue_elem_info * 16162306a36Sopenharmony_cimlxsw_pci_queue_elem_info_consumer_get(struct mlxsw_pci_queue *q) 16262306a36Sopenharmony_ci{ 16362306a36Sopenharmony_ci int index = q->consumer_counter & (q->count - 1); 16462306a36Sopenharmony_ci 16562306a36Sopenharmony_ci return mlxsw_pci_queue_elem_info_get(q, index); 16662306a36Sopenharmony_ci} 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_cistatic char *mlxsw_pci_queue_elem_get(struct mlxsw_pci_queue *q, int elem_index) 16962306a36Sopenharmony_ci{ 17062306a36Sopenharmony_ci return mlxsw_pci_queue_elem_info_get(q, elem_index)->elem; 17162306a36Sopenharmony_ci} 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_cistatic bool mlxsw_pci_elem_hw_owned(struct mlxsw_pci_queue *q, bool owner_bit) 17462306a36Sopenharmony_ci{ 17562306a36Sopenharmony_ci return owner_bit != !!(q->consumer_counter & q->count); 17662306a36Sopenharmony_ci} 17762306a36Sopenharmony_ci 17862306a36Sopenharmony_cistatic struct mlxsw_pci_queue_type_group * 17962306a36Sopenharmony_cimlxsw_pci_queue_type_group_get(struct mlxsw_pci *mlxsw_pci, 18062306a36Sopenharmony_ci enum mlxsw_pci_queue_type q_type) 18162306a36Sopenharmony_ci{ 18262306a36Sopenharmony_ci return &mlxsw_pci->queues[q_type]; 18362306a36Sopenharmony_ci} 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_cistatic u8 __mlxsw_pci_queue_count(struct mlxsw_pci *mlxsw_pci, 18662306a36Sopenharmony_ci enum mlxsw_pci_queue_type q_type) 18762306a36Sopenharmony_ci{ 18862306a36Sopenharmony_ci struct mlxsw_pci_queue_type_group *queue_group; 18962306a36Sopenharmony_ci 19062306a36Sopenharmony_ci queue_group = mlxsw_pci_queue_type_group_get(mlxsw_pci, q_type); 19162306a36Sopenharmony_ci return queue_group->count; 19262306a36Sopenharmony_ci} 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_cistatic u8 mlxsw_pci_sdq_count(struct mlxsw_pci *mlxsw_pci) 19562306a36Sopenharmony_ci{ 19662306a36Sopenharmony_ci return __mlxsw_pci_queue_count(mlxsw_pci, MLXSW_PCI_QUEUE_TYPE_SDQ); 19762306a36Sopenharmony_ci} 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_cistatic u8 mlxsw_pci_cq_count(struct mlxsw_pci *mlxsw_pci) 20062306a36Sopenharmony_ci{ 20162306a36Sopenharmony_ci return __mlxsw_pci_queue_count(mlxsw_pci, MLXSW_PCI_QUEUE_TYPE_CQ); 20262306a36Sopenharmony_ci} 20362306a36Sopenharmony_ci 20462306a36Sopenharmony_cistatic struct mlxsw_pci_queue * 20562306a36Sopenharmony_ci__mlxsw_pci_queue_get(struct mlxsw_pci *mlxsw_pci, 20662306a36Sopenharmony_ci enum mlxsw_pci_queue_type q_type, u8 q_num) 20762306a36Sopenharmony_ci{ 20862306a36Sopenharmony_ci return &mlxsw_pci->queues[q_type].q[q_num]; 20962306a36Sopenharmony_ci} 21062306a36Sopenharmony_ci 21162306a36Sopenharmony_cistatic struct mlxsw_pci_queue *mlxsw_pci_sdq_get(struct mlxsw_pci *mlxsw_pci, 21262306a36Sopenharmony_ci u8 q_num) 21362306a36Sopenharmony_ci{ 21462306a36Sopenharmony_ci return __mlxsw_pci_queue_get(mlxsw_pci, 21562306a36Sopenharmony_ci MLXSW_PCI_QUEUE_TYPE_SDQ, q_num); 21662306a36Sopenharmony_ci} 21762306a36Sopenharmony_ci 21862306a36Sopenharmony_cistatic struct mlxsw_pci_queue *mlxsw_pci_rdq_get(struct mlxsw_pci *mlxsw_pci, 21962306a36Sopenharmony_ci u8 q_num) 22062306a36Sopenharmony_ci{ 22162306a36Sopenharmony_ci return __mlxsw_pci_queue_get(mlxsw_pci, 22262306a36Sopenharmony_ci MLXSW_PCI_QUEUE_TYPE_RDQ, q_num); 22362306a36Sopenharmony_ci} 22462306a36Sopenharmony_ci 22562306a36Sopenharmony_cistatic struct mlxsw_pci_queue *mlxsw_pci_cq_get(struct mlxsw_pci *mlxsw_pci, 22662306a36Sopenharmony_ci u8 q_num) 22762306a36Sopenharmony_ci{ 22862306a36Sopenharmony_ci return __mlxsw_pci_queue_get(mlxsw_pci, MLXSW_PCI_QUEUE_TYPE_CQ, q_num); 22962306a36Sopenharmony_ci} 23062306a36Sopenharmony_ci 23162306a36Sopenharmony_cistatic struct mlxsw_pci_queue *mlxsw_pci_eq_get(struct mlxsw_pci *mlxsw_pci, 23262306a36Sopenharmony_ci u8 q_num) 23362306a36Sopenharmony_ci{ 23462306a36Sopenharmony_ci return __mlxsw_pci_queue_get(mlxsw_pci, MLXSW_PCI_QUEUE_TYPE_EQ, q_num); 23562306a36Sopenharmony_ci} 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_cistatic void __mlxsw_pci_queue_doorbell_set(struct mlxsw_pci *mlxsw_pci, 23862306a36Sopenharmony_ci struct mlxsw_pci_queue *q, 23962306a36Sopenharmony_ci u16 val) 24062306a36Sopenharmony_ci{ 24162306a36Sopenharmony_ci mlxsw_pci_write32(mlxsw_pci, 24262306a36Sopenharmony_ci DOORBELL(mlxsw_pci->doorbell_offset, 24362306a36Sopenharmony_ci mlxsw_pci_doorbell_type_offset[q->type], 24462306a36Sopenharmony_ci q->num), val); 24562306a36Sopenharmony_ci} 24662306a36Sopenharmony_ci 24762306a36Sopenharmony_cistatic void __mlxsw_pci_queue_doorbell_arm_set(struct mlxsw_pci *mlxsw_pci, 24862306a36Sopenharmony_ci struct mlxsw_pci_queue *q, 24962306a36Sopenharmony_ci u16 val) 25062306a36Sopenharmony_ci{ 25162306a36Sopenharmony_ci mlxsw_pci_write32(mlxsw_pci, 25262306a36Sopenharmony_ci DOORBELL(mlxsw_pci->doorbell_offset, 25362306a36Sopenharmony_ci mlxsw_pci_doorbell_arm_type_offset[q->type], 25462306a36Sopenharmony_ci q->num), val); 25562306a36Sopenharmony_ci} 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_cistatic void mlxsw_pci_queue_doorbell_producer_ring(struct mlxsw_pci *mlxsw_pci, 25862306a36Sopenharmony_ci struct mlxsw_pci_queue *q) 25962306a36Sopenharmony_ci{ 26062306a36Sopenharmony_ci wmb(); /* ensure all writes are done before we ring a bell */ 26162306a36Sopenharmony_ci __mlxsw_pci_queue_doorbell_set(mlxsw_pci, q, q->producer_counter); 26262306a36Sopenharmony_ci} 26362306a36Sopenharmony_ci 26462306a36Sopenharmony_cistatic void mlxsw_pci_queue_doorbell_consumer_ring(struct mlxsw_pci *mlxsw_pci, 26562306a36Sopenharmony_ci struct mlxsw_pci_queue *q) 26662306a36Sopenharmony_ci{ 26762306a36Sopenharmony_ci wmb(); /* ensure all writes are done before we ring a bell */ 26862306a36Sopenharmony_ci __mlxsw_pci_queue_doorbell_set(mlxsw_pci, q, 26962306a36Sopenharmony_ci q->consumer_counter + q->count); 27062306a36Sopenharmony_ci} 27162306a36Sopenharmony_ci 27262306a36Sopenharmony_cistatic void 27362306a36Sopenharmony_cimlxsw_pci_queue_doorbell_arm_consumer_ring(struct mlxsw_pci *mlxsw_pci, 27462306a36Sopenharmony_ci struct mlxsw_pci_queue *q) 27562306a36Sopenharmony_ci{ 27662306a36Sopenharmony_ci wmb(); /* ensure all writes are done before we ring a bell */ 27762306a36Sopenharmony_ci __mlxsw_pci_queue_doorbell_arm_set(mlxsw_pci, q, q->consumer_counter); 27862306a36Sopenharmony_ci} 27962306a36Sopenharmony_ci 28062306a36Sopenharmony_cistatic dma_addr_t __mlxsw_pci_queue_page_get(struct mlxsw_pci_queue *q, 28162306a36Sopenharmony_ci int page_index) 28262306a36Sopenharmony_ci{ 28362306a36Sopenharmony_ci return q->mem_item.mapaddr + MLXSW_PCI_PAGE_SIZE * page_index; 28462306a36Sopenharmony_ci} 28562306a36Sopenharmony_ci 28662306a36Sopenharmony_cistatic int mlxsw_pci_sdq_init(struct mlxsw_pci *mlxsw_pci, char *mbox, 28762306a36Sopenharmony_ci struct mlxsw_pci_queue *q) 28862306a36Sopenharmony_ci{ 28962306a36Sopenharmony_ci int tclass; 29062306a36Sopenharmony_ci int lp; 29162306a36Sopenharmony_ci int i; 29262306a36Sopenharmony_ci int err; 29362306a36Sopenharmony_ci 29462306a36Sopenharmony_ci q->producer_counter = 0; 29562306a36Sopenharmony_ci q->consumer_counter = 0; 29662306a36Sopenharmony_ci tclass = q->num == MLXSW_PCI_SDQ_EMAD_INDEX ? MLXSW_PCI_SDQ_EMAD_TC : 29762306a36Sopenharmony_ci MLXSW_PCI_SDQ_CTL_TC; 29862306a36Sopenharmony_ci lp = q->num == MLXSW_PCI_SDQ_EMAD_INDEX ? MLXSW_CMD_MBOX_SW2HW_DQ_SDQ_LP_IGNORE_WQE : 29962306a36Sopenharmony_ci MLXSW_CMD_MBOX_SW2HW_DQ_SDQ_LP_WQE; 30062306a36Sopenharmony_ci 30162306a36Sopenharmony_ci /* Set CQ of same number of this SDQ. */ 30262306a36Sopenharmony_ci mlxsw_cmd_mbox_sw2hw_dq_cq_set(mbox, q->num); 30362306a36Sopenharmony_ci mlxsw_cmd_mbox_sw2hw_dq_sdq_lp_set(mbox, lp); 30462306a36Sopenharmony_ci mlxsw_cmd_mbox_sw2hw_dq_sdq_tclass_set(mbox, tclass); 30562306a36Sopenharmony_ci mlxsw_cmd_mbox_sw2hw_dq_log2_dq_sz_set(mbox, 3); /* 8 pages */ 30662306a36Sopenharmony_ci for (i = 0; i < MLXSW_PCI_AQ_PAGES; i++) { 30762306a36Sopenharmony_ci dma_addr_t mapaddr = __mlxsw_pci_queue_page_get(q, i); 30862306a36Sopenharmony_ci 30962306a36Sopenharmony_ci mlxsw_cmd_mbox_sw2hw_dq_pa_set(mbox, i, mapaddr); 31062306a36Sopenharmony_ci } 31162306a36Sopenharmony_ci 31262306a36Sopenharmony_ci err = mlxsw_cmd_sw2hw_sdq(mlxsw_pci->core, mbox, q->num); 31362306a36Sopenharmony_ci if (err) 31462306a36Sopenharmony_ci return err; 31562306a36Sopenharmony_ci mlxsw_pci_queue_doorbell_producer_ring(mlxsw_pci, q); 31662306a36Sopenharmony_ci return 0; 31762306a36Sopenharmony_ci} 31862306a36Sopenharmony_ci 31962306a36Sopenharmony_cistatic void mlxsw_pci_sdq_fini(struct mlxsw_pci *mlxsw_pci, 32062306a36Sopenharmony_ci struct mlxsw_pci_queue *q) 32162306a36Sopenharmony_ci{ 32262306a36Sopenharmony_ci mlxsw_cmd_hw2sw_sdq(mlxsw_pci->core, q->num); 32362306a36Sopenharmony_ci} 32462306a36Sopenharmony_ci 32562306a36Sopenharmony_cistatic int mlxsw_pci_wqe_frag_map(struct mlxsw_pci *mlxsw_pci, char *wqe, 32662306a36Sopenharmony_ci int index, char *frag_data, size_t frag_len, 32762306a36Sopenharmony_ci int direction) 32862306a36Sopenharmony_ci{ 32962306a36Sopenharmony_ci struct pci_dev *pdev = mlxsw_pci->pdev; 33062306a36Sopenharmony_ci dma_addr_t mapaddr; 33162306a36Sopenharmony_ci 33262306a36Sopenharmony_ci mapaddr = dma_map_single(&pdev->dev, frag_data, frag_len, direction); 33362306a36Sopenharmony_ci if (unlikely(dma_mapping_error(&pdev->dev, mapaddr))) { 33462306a36Sopenharmony_ci dev_err_ratelimited(&pdev->dev, "failed to dma map tx frag\n"); 33562306a36Sopenharmony_ci return -EIO; 33662306a36Sopenharmony_ci } 33762306a36Sopenharmony_ci mlxsw_pci_wqe_address_set(wqe, index, mapaddr); 33862306a36Sopenharmony_ci mlxsw_pci_wqe_byte_count_set(wqe, index, frag_len); 33962306a36Sopenharmony_ci return 0; 34062306a36Sopenharmony_ci} 34162306a36Sopenharmony_ci 34262306a36Sopenharmony_cistatic void mlxsw_pci_wqe_frag_unmap(struct mlxsw_pci *mlxsw_pci, char *wqe, 34362306a36Sopenharmony_ci int index, int direction) 34462306a36Sopenharmony_ci{ 34562306a36Sopenharmony_ci struct pci_dev *pdev = mlxsw_pci->pdev; 34662306a36Sopenharmony_ci size_t frag_len = mlxsw_pci_wqe_byte_count_get(wqe, index); 34762306a36Sopenharmony_ci dma_addr_t mapaddr = mlxsw_pci_wqe_address_get(wqe, index); 34862306a36Sopenharmony_ci 34962306a36Sopenharmony_ci if (!frag_len) 35062306a36Sopenharmony_ci return; 35162306a36Sopenharmony_ci dma_unmap_single(&pdev->dev, mapaddr, frag_len, direction); 35262306a36Sopenharmony_ci} 35362306a36Sopenharmony_ci 35462306a36Sopenharmony_cistatic int mlxsw_pci_rdq_skb_alloc(struct mlxsw_pci *mlxsw_pci, 35562306a36Sopenharmony_ci struct mlxsw_pci_queue_elem_info *elem_info) 35662306a36Sopenharmony_ci{ 35762306a36Sopenharmony_ci size_t buf_len = MLXSW_PORT_MAX_MTU; 35862306a36Sopenharmony_ci char *wqe = elem_info->elem; 35962306a36Sopenharmony_ci struct sk_buff *skb; 36062306a36Sopenharmony_ci int err; 36162306a36Sopenharmony_ci 36262306a36Sopenharmony_ci skb = netdev_alloc_skb_ip_align(NULL, buf_len); 36362306a36Sopenharmony_ci if (!skb) 36462306a36Sopenharmony_ci return -ENOMEM; 36562306a36Sopenharmony_ci 36662306a36Sopenharmony_ci err = mlxsw_pci_wqe_frag_map(mlxsw_pci, wqe, 0, skb->data, 36762306a36Sopenharmony_ci buf_len, DMA_FROM_DEVICE); 36862306a36Sopenharmony_ci if (err) 36962306a36Sopenharmony_ci goto err_frag_map; 37062306a36Sopenharmony_ci 37162306a36Sopenharmony_ci elem_info->u.rdq.skb = skb; 37262306a36Sopenharmony_ci return 0; 37362306a36Sopenharmony_ci 37462306a36Sopenharmony_cierr_frag_map: 37562306a36Sopenharmony_ci dev_kfree_skb_any(skb); 37662306a36Sopenharmony_ci return err; 37762306a36Sopenharmony_ci} 37862306a36Sopenharmony_ci 37962306a36Sopenharmony_cistatic void mlxsw_pci_rdq_skb_free(struct mlxsw_pci *mlxsw_pci, 38062306a36Sopenharmony_ci struct mlxsw_pci_queue_elem_info *elem_info) 38162306a36Sopenharmony_ci{ 38262306a36Sopenharmony_ci struct sk_buff *skb; 38362306a36Sopenharmony_ci char *wqe; 38462306a36Sopenharmony_ci 38562306a36Sopenharmony_ci skb = elem_info->u.rdq.skb; 38662306a36Sopenharmony_ci wqe = elem_info->elem; 38762306a36Sopenharmony_ci 38862306a36Sopenharmony_ci mlxsw_pci_wqe_frag_unmap(mlxsw_pci, wqe, 0, DMA_FROM_DEVICE); 38962306a36Sopenharmony_ci dev_kfree_skb_any(skb); 39062306a36Sopenharmony_ci} 39162306a36Sopenharmony_ci 39262306a36Sopenharmony_cistatic int mlxsw_pci_rdq_init(struct mlxsw_pci *mlxsw_pci, char *mbox, 39362306a36Sopenharmony_ci struct mlxsw_pci_queue *q) 39462306a36Sopenharmony_ci{ 39562306a36Sopenharmony_ci struct mlxsw_pci_queue_elem_info *elem_info; 39662306a36Sopenharmony_ci u8 sdq_count = mlxsw_pci_sdq_count(mlxsw_pci); 39762306a36Sopenharmony_ci int i; 39862306a36Sopenharmony_ci int err; 39962306a36Sopenharmony_ci 40062306a36Sopenharmony_ci q->producer_counter = 0; 40162306a36Sopenharmony_ci q->consumer_counter = 0; 40262306a36Sopenharmony_ci 40362306a36Sopenharmony_ci /* Set CQ of same number of this RDQ with base 40462306a36Sopenharmony_ci * above SDQ count as the lower ones are assigned to SDQs. 40562306a36Sopenharmony_ci */ 40662306a36Sopenharmony_ci mlxsw_cmd_mbox_sw2hw_dq_cq_set(mbox, sdq_count + q->num); 40762306a36Sopenharmony_ci mlxsw_cmd_mbox_sw2hw_dq_log2_dq_sz_set(mbox, 3); /* 8 pages */ 40862306a36Sopenharmony_ci for (i = 0; i < MLXSW_PCI_AQ_PAGES; i++) { 40962306a36Sopenharmony_ci dma_addr_t mapaddr = __mlxsw_pci_queue_page_get(q, i); 41062306a36Sopenharmony_ci 41162306a36Sopenharmony_ci mlxsw_cmd_mbox_sw2hw_dq_pa_set(mbox, i, mapaddr); 41262306a36Sopenharmony_ci } 41362306a36Sopenharmony_ci 41462306a36Sopenharmony_ci err = mlxsw_cmd_sw2hw_rdq(mlxsw_pci->core, mbox, q->num); 41562306a36Sopenharmony_ci if (err) 41662306a36Sopenharmony_ci return err; 41762306a36Sopenharmony_ci 41862306a36Sopenharmony_ci mlxsw_pci_queue_doorbell_producer_ring(mlxsw_pci, q); 41962306a36Sopenharmony_ci 42062306a36Sopenharmony_ci for (i = 0; i < q->count; i++) { 42162306a36Sopenharmony_ci elem_info = mlxsw_pci_queue_elem_info_producer_get(q); 42262306a36Sopenharmony_ci BUG_ON(!elem_info); 42362306a36Sopenharmony_ci err = mlxsw_pci_rdq_skb_alloc(mlxsw_pci, elem_info); 42462306a36Sopenharmony_ci if (err) 42562306a36Sopenharmony_ci goto rollback; 42662306a36Sopenharmony_ci /* Everything is set up, ring doorbell to pass elem to HW */ 42762306a36Sopenharmony_ci q->producer_counter++; 42862306a36Sopenharmony_ci mlxsw_pci_queue_doorbell_producer_ring(mlxsw_pci, q); 42962306a36Sopenharmony_ci } 43062306a36Sopenharmony_ci 43162306a36Sopenharmony_ci return 0; 43262306a36Sopenharmony_ci 43362306a36Sopenharmony_cirollback: 43462306a36Sopenharmony_ci for (i--; i >= 0; i--) { 43562306a36Sopenharmony_ci elem_info = mlxsw_pci_queue_elem_info_get(q, i); 43662306a36Sopenharmony_ci mlxsw_pci_rdq_skb_free(mlxsw_pci, elem_info); 43762306a36Sopenharmony_ci } 43862306a36Sopenharmony_ci mlxsw_cmd_hw2sw_rdq(mlxsw_pci->core, q->num); 43962306a36Sopenharmony_ci 44062306a36Sopenharmony_ci return err; 44162306a36Sopenharmony_ci} 44262306a36Sopenharmony_ci 44362306a36Sopenharmony_cistatic void mlxsw_pci_rdq_fini(struct mlxsw_pci *mlxsw_pci, 44462306a36Sopenharmony_ci struct mlxsw_pci_queue *q) 44562306a36Sopenharmony_ci{ 44662306a36Sopenharmony_ci struct mlxsw_pci_queue_elem_info *elem_info; 44762306a36Sopenharmony_ci int i; 44862306a36Sopenharmony_ci 44962306a36Sopenharmony_ci mlxsw_cmd_hw2sw_rdq(mlxsw_pci->core, q->num); 45062306a36Sopenharmony_ci for (i = 0; i < q->count; i++) { 45162306a36Sopenharmony_ci elem_info = mlxsw_pci_queue_elem_info_get(q, i); 45262306a36Sopenharmony_ci mlxsw_pci_rdq_skb_free(mlxsw_pci, elem_info); 45362306a36Sopenharmony_ci } 45462306a36Sopenharmony_ci} 45562306a36Sopenharmony_ci 45662306a36Sopenharmony_cistatic void mlxsw_pci_cq_pre_init(struct mlxsw_pci *mlxsw_pci, 45762306a36Sopenharmony_ci struct mlxsw_pci_queue *q) 45862306a36Sopenharmony_ci{ 45962306a36Sopenharmony_ci q->u.cq.v = mlxsw_pci->max_cqe_ver; 46062306a36Sopenharmony_ci 46162306a36Sopenharmony_ci if (q->u.cq.v == MLXSW_PCI_CQE_V2 && 46262306a36Sopenharmony_ci q->num < mlxsw_pci->num_sdq_cqs && 46362306a36Sopenharmony_ci !mlxsw_core_sdq_supports_cqe_v2(mlxsw_pci->core)) 46462306a36Sopenharmony_ci q->u.cq.v = MLXSW_PCI_CQE_V1; 46562306a36Sopenharmony_ci} 46662306a36Sopenharmony_ci 46762306a36Sopenharmony_cistatic int mlxsw_pci_cq_init(struct mlxsw_pci *mlxsw_pci, char *mbox, 46862306a36Sopenharmony_ci struct mlxsw_pci_queue *q) 46962306a36Sopenharmony_ci{ 47062306a36Sopenharmony_ci int i; 47162306a36Sopenharmony_ci int err; 47262306a36Sopenharmony_ci 47362306a36Sopenharmony_ci q->consumer_counter = 0; 47462306a36Sopenharmony_ci 47562306a36Sopenharmony_ci for (i = 0; i < q->count; i++) { 47662306a36Sopenharmony_ci char *elem = mlxsw_pci_queue_elem_get(q, i); 47762306a36Sopenharmony_ci 47862306a36Sopenharmony_ci mlxsw_pci_cqe_owner_set(q->u.cq.v, elem, 1); 47962306a36Sopenharmony_ci } 48062306a36Sopenharmony_ci 48162306a36Sopenharmony_ci if (q->u.cq.v == MLXSW_PCI_CQE_V1) 48262306a36Sopenharmony_ci mlxsw_cmd_mbox_sw2hw_cq_cqe_ver_set(mbox, 48362306a36Sopenharmony_ci MLXSW_CMD_MBOX_SW2HW_CQ_CQE_VER_1); 48462306a36Sopenharmony_ci else if (q->u.cq.v == MLXSW_PCI_CQE_V2) 48562306a36Sopenharmony_ci mlxsw_cmd_mbox_sw2hw_cq_cqe_ver_set(mbox, 48662306a36Sopenharmony_ci MLXSW_CMD_MBOX_SW2HW_CQ_CQE_VER_2); 48762306a36Sopenharmony_ci 48862306a36Sopenharmony_ci mlxsw_cmd_mbox_sw2hw_cq_c_eqn_set(mbox, MLXSW_PCI_EQ_COMP_NUM); 48962306a36Sopenharmony_ci mlxsw_cmd_mbox_sw2hw_cq_st_set(mbox, 0); 49062306a36Sopenharmony_ci mlxsw_cmd_mbox_sw2hw_cq_log_cq_size_set(mbox, ilog2(q->count)); 49162306a36Sopenharmony_ci for (i = 0; i < MLXSW_PCI_AQ_PAGES; i++) { 49262306a36Sopenharmony_ci dma_addr_t mapaddr = __mlxsw_pci_queue_page_get(q, i); 49362306a36Sopenharmony_ci 49462306a36Sopenharmony_ci mlxsw_cmd_mbox_sw2hw_cq_pa_set(mbox, i, mapaddr); 49562306a36Sopenharmony_ci } 49662306a36Sopenharmony_ci err = mlxsw_cmd_sw2hw_cq(mlxsw_pci->core, mbox, q->num); 49762306a36Sopenharmony_ci if (err) 49862306a36Sopenharmony_ci return err; 49962306a36Sopenharmony_ci mlxsw_pci_queue_doorbell_consumer_ring(mlxsw_pci, q); 50062306a36Sopenharmony_ci mlxsw_pci_queue_doorbell_arm_consumer_ring(mlxsw_pci, q); 50162306a36Sopenharmony_ci return 0; 50262306a36Sopenharmony_ci} 50362306a36Sopenharmony_ci 50462306a36Sopenharmony_cistatic void mlxsw_pci_cq_fini(struct mlxsw_pci *mlxsw_pci, 50562306a36Sopenharmony_ci struct mlxsw_pci_queue *q) 50662306a36Sopenharmony_ci{ 50762306a36Sopenharmony_ci mlxsw_cmd_hw2sw_cq(mlxsw_pci->core, q->num); 50862306a36Sopenharmony_ci} 50962306a36Sopenharmony_ci 51062306a36Sopenharmony_cistatic unsigned int mlxsw_pci_read32_off(struct mlxsw_pci *mlxsw_pci, 51162306a36Sopenharmony_ci ptrdiff_t off) 51262306a36Sopenharmony_ci{ 51362306a36Sopenharmony_ci return ioread32be(mlxsw_pci->hw_addr + off); 51462306a36Sopenharmony_ci} 51562306a36Sopenharmony_ci 51662306a36Sopenharmony_cistatic void mlxsw_pci_skb_cb_ts_set(struct mlxsw_pci *mlxsw_pci, 51762306a36Sopenharmony_ci struct sk_buff *skb, 51862306a36Sopenharmony_ci enum mlxsw_pci_cqe_v cqe_v, char *cqe) 51962306a36Sopenharmony_ci{ 52062306a36Sopenharmony_ci u8 ts_type; 52162306a36Sopenharmony_ci 52262306a36Sopenharmony_ci if (cqe_v != MLXSW_PCI_CQE_V2) 52362306a36Sopenharmony_ci return; 52462306a36Sopenharmony_ci 52562306a36Sopenharmony_ci ts_type = mlxsw_pci_cqe2_time_stamp_type_get(cqe); 52662306a36Sopenharmony_ci 52762306a36Sopenharmony_ci if (ts_type != MLXSW_PCI_CQE_TIME_STAMP_TYPE_UTC && 52862306a36Sopenharmony_ci ts_type != MLXSW_PCI_CQE_TIME_STAMP_TYPE_MIRROR_UTC) 52962306a36Sopenharmony_ci return; 53062306a36Sopenharmony_ci 53162306a36Sopenharmony_ci mlxsw_skb_cb(skb)->cqe_ts.sec = mlxsw_pci_cqe2_time_stamp_sec_get(cqe); 53262306a36Sopenharmony_ci mlxsw_skb_cb(skb)->cqe_ts.nsec = 53362306a36Sopenharmony_ci mlxsw_pci_cqe2_time_stamp_nsec_get(cqe); 53462306a36Sopenharmony_ci} 53562306a36Sopenharmony_ci 53662306a36Sopenharmony_cistatic void mlxsw_pci_cqe_sdq_handle(struct mlxsw_pci *mlxsw_pci, 53762306a36Sopenharmony_ci struct mlxsw_pci_queue *q, 53862306a36Sopenharmony_ci u16 consumer_counter_limit, 53962306a36Sopenharmony_ci enum mlxsw_pci_cqe_v cqe_v, 54062306a36Sopenharmony_ci char *cqe) 54162306a36Sopenharmony_ci{ 54262306a36Sopenharmony_ci struct pci_dev *pdev = mlxsw_pci->pdev; 54362306a36Sopenharmony_ci struct mlxsw_pci_queue_elem_info *elem_info; 54462306a36Sopenharmony_ci struct mlxsw_tx_info tx_info; 54562306a36Sopenharmony_ci char *wqe; 54662306a36Sopenharmony_ci struct sk_buff *skb; 54762306a36Sopenharmony_ci int i; 54862306a36Sopenharmony_ci 54962306a36Sopenharmony_ci spin_lock(&q->lock); 55062306a36Sopenharmony_ci elem_info = mlxsw_pci_queue_elem_info_consumer_get(q); 55162306a36Sopenharmony_ci tx_info = mlxsw_skb_cb(elem_info->u.sdq.skb)->tx_info; 55262306a36Sopenharmony_ci skb = elem_info->u.sdq.skb; 55362306a36Sopenharmony_ci wqe = elem_info->elem; 55462306a36Sopenharmony_ci for (i = 0; i < MLXSW_PCI_WQE_SG_ENTRIES; i++) 55562306a36Sopenharmony_ci mlxsw_pci_wqe_frag_unmap(mlxsw_pci, wqe, i, DMA_TO_DEVICE); 55662306a36Sopenharmony_ci 55762306a36Sopenharmony_ci if (unlikely(!tx_info.is_emad && 55862306a36Sopenharmony_ci skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP)) { 55962306a36Sopenharmony_ci mlxsw_pci_skb_cb_ts_set(mlxsw_pci, skb, cqe_v, cqe); 56062306a36Sopenharmony_ci mlxsw_core_ptp_transmitted(mlxsw_pci->core, skb, 56162306a36Sopenharmony_ci tx_info.local_port); 56262306a36Sopenharmony_ci skb = NULL; 56362306a36Sopenharmony_ci } 56462306a36Sopenharmony_ci 56562306a36Sopenharmony_ci if (skb) 56662306a36Sopenharmony_ci dev_kfree_skb_any(skb); 56762306a36Sopenharmony_ci elem_info->u.sdq.skb = NULL; 56862306a36Sopenharmony_ci 56962306a36Sopenharmony_ci if (q->consumer_counter++ != consumer_counter_limit) 57062306a36Sopenharmony_ci dev_dbg_ratelimited(&pdev->dev, "Consumer counter does not match limit in SDQ\n"); 57162306a36Sopenharmony_ci spin_unlock(&q->lock); 57262306a36Sopenharmony_ci} 57362306a36Sopenharmony_ci 57462306a36Sopenharmony_cistatic void mlxsw_pci_cqe_rdq_md_tx_port_init(struct sk_buff *skb, 57562306a36Sopenharmony_ci const char *cqe) 57662306a36Sopenharmony_ci{ 57762306a36Sopenharmony_ci struct mlxsw_skb_cb *cb = mlxsw_skb_cb(skb); 57862306a36Sopenharmony_ci 57962306a36Sopenharmony_ci if (mlxsw_pci_cqe2_tx_lag_get(cqe)) { 58062306a36Sopenharmony_ci cb->rx_md_info.tx_port_is_lag = true; 58162306a36Sopenharmony_ci cb->rx_md_info.tx_lag_id = mlxsw_pci_cqe2_tx_lag_id_get(cqe); 58262306a36Sopenharmony_ci cb->rx_md_info.tx_lag_port_index = 58362306a36Sopenharmony_ci mlxsw_pci_cqe2_tx_lag_subport_get(cqe); 58462306a36Sopenharmony_ci } else { 58562306a36Sopenharmony_ci cb->rx_md_info.tx_port_is_lag = false; 58662306a36Sopenharmony_ci cb->rx_md_info.tx_sys_port = 58762306a36Sopenharmony_ci mlxsw_pci_cqe2_tx_system_port_get(cqe); 58862306a36Sopenharmony_ci } 58962306a36Sopenharmony_ci 59062306a36Sopenharmony_ci if (cb->rx_md_info.tx_sys_port != MLXSW_PCI_CQE2_TX_PORT_MULTI_PORT && 59162306a36Sopenharmony_ci cb->rx_md_info.tx_sys_port != MLXSW_PCI_CQE2_TX_PORT_INVALID) 59262306a36Sopenharmony_ci cb->rx_md_info.tx_port_valid = 1; 59362306a36Sopenharmony_ci else 59462306a36Sopenharmony_ci cb->rx_md_info.tx_port_valid = 0; 59562306a36Sopenharmony_ci} 59662306a36Sopenharmony_ci 59762306a36Sopenharmony_cistatic void mlxsw_pci_cqe_rdq_md_init(struct sk_buff *skb, const char *cqe) 59862306a36Sopenharmony_ci{ 59962306a36Sopenharmony_ci struct mlxsw_skb_cb *cb = mlxsw_skb_cb(skb); 60062306a36Sopenharmony_ci 60162306a36Sopenharmony_ci cb->rx_md_info.tx_congestion = mlxsw_pci_cqe2_mirror_cong_get(cqe); 60262306a36Sopenharmony_ci if (cb->rx_md_info.tx_congestion != MLXSW_PCI_CQE2_MIRROR_CONG_INVALID) 60362306a36Sopenharmony_ci cb->rx_md_info.tx_congestion_valid = 1; 60462306a36Sopenharmony_ci else 60562306a36Sopenharmony_ci cb->rx_md_info.tx_congestion_valid = 0; 60662306a36Sopenharmony_ci cb->rx_md_info.tx_congestion <<= MLXSW_PCI_CQE2_MIRROR_CONG_SHIFT; 60762306a36Sopenharmony_ci 60862306a36Sopenharmony_ci cb->rx_md_info.latency = mlxsw_pci_cqe2_mirror_latency_get(cqe); 60962306a36Sopenharmony_ci if (cb->rx_md_info.latency != MLXSW_PCI_CQE2_MIRROR_LATENCY_INVALID) 61062306a36Sopenharmony_ci cb->rx_md_info.latency_valid = 1; 61162306a36Sopenharmony_ci else 61262306a36Sopenharmony_ci cb->rx_md_info.latency_valid = 0; 61362306a36Sopenharmony_ci 61462306a36Sopenharmony_ci cb->rx_md_info.tx_tc = mlxsw_pci_cqe2_mirror_tclass_get(cqe); 61562306a36Sopenharmony_ci if (cb->rx_md_info.tx_tc != MLXSW_PCI_CQE2_MIRROR_TCLASS_INVALID) 61662306a36Sopenharmony_ci cb->rx_md_info.tx_tc_valid = 1; 61762306a36Sopenharmony_ci else 61862306a36Sopenharmony_ci cb->rx_md_info.tx_tc_valid = 0; 61962306a36Sopenharmony_ci 62062306a36Sopenharmony_ci mlxsw_pci_cqe_rdq_md_tx_port_init(skb, cqe); 62162306a36Sopenharmony_ci} 62262306a36Sopenharmony_ci 62362306a36Sopenharmony_cistatic void mlxsw_pci_cqe_rdq_handle(struct mlxsw_pci *mlxsw_pci, 62462306a36Sopenharmony_ci struct mlxsw_pci_queue *q, 62562306a36Sopenharmony_ci u16 consumer_counter_limit, 62662306a36Sopenharmony_ci enum mlxsw_pci_cqe_v cqe_v, char *cqe) 62762306a36Sopenharmony_ci{ 62862306a36Sopenharmony_ci struct pci_dev *pdev = mlxsw_pci->pdev; 62962306a36Sopenharmony_ci struct mlxsw_pci_queue_elem_info *elem_info; 63062306a36Sopenharmony_ci struct mlxsw_rx_info rx_info = {}; 63162306a36Sopenharmony_ci char wqe[MLXSW_PCI_WQE_SIZE]; 63262306a36Sopenharmony_ci struct sk_buff *skb; 63362306a36Sopenharmony_ci u16 byte_count; 63462306a36Sopenharmony_ci int err; 63562306a36Sopenharmony_ci 63662306a36Sopenharmony_ci elem_info = mlxsw_pci_queue_elem_info_consumer_get(q); 63762306a36Sopenharmony_ci skb = elem_info->u.rdq.skb; 63862306a36Sopenharmony_ci memcpy(wqe, elem_info->elem, MLXSW_PCI_WQE_SIZE); 63962306a36Sopenharmony_ci 64062306a36Sopenharmony_ci if (q->consumer_counter++ != consumer_counter_limit) 64162306a36Sopenharmony_ci dev_dbg_ratelimited(&pdev->dev, "Consumer counter does not match limit in RDQ\n"); 64262306a36Sopenharmony_ci 64362306a36Sopenharmony_ci err = mlxsw_pci_rdq_skb_alloc(mlxsw_pci, elem_info); 64462306a36Sopenharmony_ci if (err) { 64562306a36Sopenharmony_ci dev_err_ratelimited(&pdev->dev, "Failed to alloc skb for RDQ\n"); 64662306a36Sopenharmony_ci goto out; 64762306a36Sopenharmony_ci } 64862306a36Sopenharmony_ci 64962306a36Sopenharmony_ci mlxsw_pci_wqe_frag_unmap(mlxsw_pci, wqe, 0, DMA_FROM_DEVICE); 65062306a36Sopenharmony_ci 65162306a36Sopenharmony_ci if (mlxsw_pci_cqe_lag_get(cqe_v, cqe)) { 65262306a36Sopenharmony_ci rx_info.is_lag = true; 65362306a36Sopenharmony_ci rx_info.u.lag_id = mlxsw_pci_cqe_lag_id_get(cqe_v, cqe); 65462306a36Sopenharmony_ci rx_info.lag_port_index = 65562306a36Sopenharmony_ci mlxsw_pci_cqe_lag_subport_get(cqe_v, cqe); 65662306a36Sopenharmony_ci } else { 65762306a36Sopenharmony_ci rx_info.is_lag = false; 65862306a36Sopenharmony_ci rx_info.u.sys_port = mlxsw_pci_cqe_system_port_get(cqe); 65962306a36Sopenharmony_ci } 66062306a36Sopenharmony_ci 66162306a36Sopenharmony_ci rx_info.trap_id = mlxsw_pci_cqe_trap_id_get(cqe); 66262306a36Sopenharmony_ci 66362306a36Sopenharmony_ci if (rx_info.trap_id == MLXSW_TRAP_ID_DISCARD_INGRESS_ACL || 66462306a36Sopenharmony_ci rx_info.trap_id == MLXSW_TRAP_ID_DISCARD_EGRESS_ACL) { 66562306a36Sopenharmony_ci u32 cookie_index = 0; 66662306a36Sopenharmony_ci 66762306a36Sopenharmony_ci if (mlxsw_pci->max_cqe_ver >= MLXSW_PCI_CQE_V2) 66862306a36Sopenharmony_ci cookie_index = mlxsw_pci_cqe2_user_def_val_orig_pkt_len_get(cqe); 66962306a36Sopenharmony_ci mlxsw_skb_cb(skb)->rx_md_info.cookie_index = cookie_index; 67062306a36Sopenharmony_ci } else if (rx_info.trap_id >= MLXSW_TRAP_ID_MIRROR_SESSION0 && 67162306a36Sopenharmony_ci rx_info.trap_id <= MLXSW_TRAP_ID_MIRROR_SESSION7 && 67262306a36Sopenharmony_ci mlxsw_pci->max_cqe_ver >= MLXSW_PCI_CQE_V2) { 67362306a36Sopenharmony_ci rx_info.mirror_reason = mlxsw_pci_cqe2_mirror_reason_get(cqe); 67462306a36Sopenharmony_ci mlxsw_pci_cqe_rdq_md_init(skb, cqe); 67562306a36Sopenharmony_ci } else if (rx_info.trap_id == MLXSW_TRAP_ID_PKT_SAMPLE && 67662306a36Sopenharmony_ci mlxsw_pci->max_cqe_ver >= MLXSW_PCI_CQE_V2) { 67762306a36Sopenharmony_ci mlxsw_pci_cqe_rdq_md_tx_port_init(skb, cqe); 67862306a36Sopenharmony_ci } 67962306a36Sopenharmony_ci 68062306a36Sopenharmony_ci mlxsw_pci_skb_cb_ts_set(mlxsw_pci, skb, cqe_v, cqe); 68162306a36Sopenharmony_ci 68262306a36Sopenharmony_ci byte_count = mlxsw_pci_cqe_byte_count_get(cqe); 68362306a36Sopenharmony_ci if (mlxsw_pci_cqe_crc_get(cqe_v, cqe)) 68462306a36Sopenharmony_ci byte_count -= ETH_FCS_LEN; 68562306a36Sopenharmony_ci skb_put(skb, byte_count); 68662306a36Sopenharmony_ci mlxsw_core_skb_receive(mlxsw_pci->core, skb, &rx_info); 68762306a36Sopenharmony_ci 68862306a36Sopenharmony_ciout: 68962306a36Sopenharmony_ci /* Everything is set up, ring doorbell to pass elem to HW */ 69062306a36Sopenharmony_ci q->producer_counter++; 69162306a36Sopenharmony_ci mlxsw_pci_queue_doorbell_producer_ring(mlxsw_pci, q); 69262306a36Sopenharmony_ci return; 69362306a36Sopenharmony_ci} 69462306a36Sopenharmony_ci 69562306a36Sopenharmony_cistatic char *mlxsw_pci_cq_sw_cqe_get(struct mlxsw_pci_queue *q) 69662306a36Sopenharmony_ci{ 69762306a36Sopenharmony_ci struct mlxsw_pci_queue_elem_info *elem_info; 69862306a36Sopenharmony_ci char *elem; 69962306a36Sopenharmony_ci bool owner_bit; 70062306a36Sopenharmony_ci 70162306a36Sopenharmony_ci elem_info = mlxsw_pci_queue_elem_info_consumer_get(q); 70262306a36Sopenharmony_ci elem = elem_info->elem; 70362306a36Sopenharmony_ci owner_bit = mlxsw_pci_cqe_owner_get(q->u.cq.v, elem); 70462306a36Sopenharmony_ci if (mlxsw_pci_elem_hw_owned(q, owner_bit)) 70562306a36Sopenharmony_ci return NULL; 70662306a36Sopenharmony_ci q->consumer_counter++; 70762306a36Sopenharmony_ci rmb(); /* make sure we read owned bit before the rest of elem */ 70862306a36Sopenharmony_ci return elem; 70962306a36Sopenharmony_ci} 71062306a36Sopenharmony_ci 71162306a36Sopenharmony_cistatic void mlxsw_pci_cq_tasklet(struct tasklet_struct *t) 71262306a36Sopenharmony_ci{ 71362306a36Sopenharmony_ci struct mlxsw_pci_queue *q = from_tasklet(q, t, tasklet); 71462306a36Sopenharmony_ci struct mlxsw_pci *mlxsw_pci = q->pci; 71562306a36Sopenharmony_ci char *cqe; 71662306a36Sopenharmony_ci int items = 0; 71762306a36Sopenharmony_ci int credits = q->count >> 1; 71862306a36Sopenharmony_ci 71962306a36Sopenharmony_ci while ((cqe = mlxsw_pci_cq_sw_cqe_get(q))) { 72062306a36Sopenharmony_ci u16 wqe_counter = mlxsw_pci_cqe_wqe_counter_get(cqe); 72162306a36Sopenharmony_ci u8 sendq = mlxsw_pci_cqe_sr_get(q->u.cq.v, cqe); 72262306a36Sopenharmony_ci u8 dqn = mlxsw_pci_cqe_dqn_get(q->u.cq.v, cqe); 72362306a36Sopenharmony_ci char ncqe[MLXSW_PCI_CQE_SIZE_MAX]; 72462306a36Sopenharmony_ci 72562306a36Sopenharmony_ci memcpy(ncqe, cqe, q->elem_size); 72662306a36Sopenharmony_ci mlxsw_pci_queue_doorbell_consumer_ring(mlxsw_pci, q); 72762306a36Sopenharmony_ci 72862306a36Sopenharmony_ci if (sendq) { 72962306a36Sopenharmony_ci struct mlxsw_pci_queue *sdq; 73062306a36Sopenharmony_ci 73162306a36Sopenharmony_ci sdq = mlxsw_pci_sdq_get(mlxsw_pci, dqn); 73262306a36Sopenharmony_ci mlxsw_pci_cqe_sdq_handle(mlxsw_pci, sdq, 73362306a36Sopenharmony_ci wqe_counter, q->u.cq.v, ncqe); 73462306a36Sopenharmony_ci q->u.cq.comp_sdq_count++; 73562306a36Sopenharmony_ci } else { 73662306a36Sopenharmony_ci struct mlxsw_pci_queue *rdq; 73762306a36Sopenharmony_ci 73862306a36Sopenharmony_ci rdq = mlxsw_pci_rdq_get(mlxsw_pci, dqn); 73962306a36Sopenharmony_ci mlxsw_pci_cqe_rdq_handle(mlxsw_pci, rdq, 74062306a36Sopenharmony_ci wqe_counter, q->u.cq.v, ncqe); 74162306a36Sopenharmony_ci q->u.cq.comp_rdq_count++; 74262306a36Sopenharmony_ci } 74362306a36Sopenharmony_ci if (++items == credits) 74462306a36Sopenharmony_ci break; 74562306a36Sopenharmony_ci } 74662306a36Sopenharmony_ci if (items) 74762306a36Sopenharmony_ci mlxsw_pci_queue_doorbell_arm_consumer_ring(mlxsw_pci, q); 74862306a36Sopenharmony_ci} 74962306a36Sopenharmony_ci 75062306a36Sopenharmony_cistatic u16 mlxsw_pci_cq_elem_count(const struct mlxsw_pci_queue *q) 75162306a36Sopenharmony_ci{ 75262306a36Sopenharmony_ci return q->u.cq.v == MLXSW_PCI_CQE_V2 ? MLXSW_PCI_CQE2_COUNT : 75362306a36Sopenharmony_ci MLXSW_PCI_CQE01_COUNT; 75462306a36Sopenharmony_ci} 75562306a36Sopenharmony_ci 75662306a36Sopenharmony_cistatic u8 mlxsw_pci_cq_elem_size(const struct mlxsw_pci_queue *q) 75762306a36Sopenharmony_ci{ 75862306a36Sopenharmony_ci return q->u.cq.v == MLXSW_PCI_CQE_V2 ? MLXSW_PCI_CQE2_SIZE : 75962306a36Sopenharmony_ci MLXSW_PCI_CQE01_SIZE; 76062306a36Sopenharmony_ci} 76162306a36Sopenharmony_ci 76262306a36Sopenharmony_cistatic int mlxsw_pci_eq_init(struct mlxsw_pci *mlxsw_pci, char *mbox, 76362306a36Sopenharmony_ci struct mlxsw_pci_queue *q) 76462306a36Sopenharmony_ci{ 76562306a36Sopenharmony_ci int i; 76662306a36Sopenharmony_ci int err; 76762306a36Sopenharmony_ci 76862306a36Sopenharmony_ci q->consumer_counter = 0; 76962306a36Sopenharmony_ci 77062306a36Sopenharmony_ci for (i = 0; i < q->count; i++) { 77162306a36Sopenharmony_ci char *elem = mlxsw_pci_queue_elem_get(q, i); 77262306a36Sopenharmony_ci 77362306a36Sopenharmony_ci mlxsw_pci_eqe_owner_set(elem, 1); 77462306a36Sopenharmony_ci } 77562306a36Sopenharmony_ci 77662306a36Sopenharmony_ci mlxsw_cmd_mbox_sw2hw_eq_int_msix_set(mbox, 1); /* MSI-X used */ 77762306a36Sopenharmony_ci mlxsw_cmd_mbox_sw2hw_eq_st_set(mbox, 1); /* armed */ 77862306a36Sopenharmony_ci mlxsw_cmd_mbox_sw2hw_eq_log_eq_size_set(mbox, ilog2(q->count)); 77962306a36Sopenharmony_ci for (i = 0; i < MLXSW_PCI_AQ_PAGES; i++) { 78062306a36Sopenharmony_ci dma_addr_t mapaddr = __mlxsw_pci_queue_page_get(q, i); 78162306a36Sopenharmony_ci 78262306a36Sopenharmony_ci mlxsw_cmd_mbox_sw2hw_eq_pa_set(mbox, i, mapaddr); 78362306a36Sopenharmony_ci } 78462306a36Sopenharmony_ci err = mlxsw_cmd_sw2hw_eq(mlxsw_pci->core, mbox, q->num); 78562306a36Sopenharmony_ci if (err) 78662306a36Sopenharmony_ci return err; 78762306a36Sopenharmony_ci mlxsw_pci_queue_doorbell_consumer_ring(mlxsw_pci, q); 78862306a36Sopenharmony_ci mlxsw_pci_queue_doorbell_arm_consumer_ring(mlxsw_pci, q); 78962306a36Sopenharmony_ci return 0; 79062306a36Sopenharmony_ci} 79162306a36Sopenharmony_ci 79262306a36Sopenharmony_cistatic void mlxsw_pci_eq_fini(struct mlxsw_pci *mlxsw_pci, 79362306a36Sopenharmony_ci struct mlxsw_pci_queue *q) 79462306a36Sopenharmony_ci{ 79562306a36Sopenharmony_ci mlxsw_cmd_hw2sw_eq(mlxsw_pci->core, q->num); 79662306a36Sopenharmony_ci} 79762306a36Sopenharmony_ci 79862306a36Sopenharmony_cistatic void mlxsw_pci_eq_cmd_event(struct mlxsw_pci *mlxsw_pci, char *eqe) 79962306a36Sopenharmony_ci{ 80062306a36Sopenharmony_ci mlxsw_pci->cmd.comp.status = mlxsw_pci_eqe_cmd_status_get(eqe); 80162306a36Sopenharmony_ci mlxsw_pci->cmd.comp.out_param = 80262306a36Sopenharmony_ci ((u64) mlxsw_pci_eqe_cmd_out_param_h_get(eqe)) << 32 | 80362306a36Sopenharmony_ci mlxsw_pci_eqe_cmd_out_param_l_get(eqe); 80462306a36Sopenharmony_ci mlxsw_pci->cmd.wait_done = true; 80562306a36Sopenharmony_ci wake_up(&mlxsw_pci->cmd.wait); 80662306a36Sopenharmony_ci} 80762306a36Sopenharmony_ci 80862306a36Sopenharmony_cistatic char *mlxsw_pci_eq_sw_eqe_get(struct mlxsw_pci_queue *q) 80962306a36Sopenharmony_ci{ 81062306a36Sopenharmony_ci struct mlxsw_pci_queue_elem_info *elem_info; 81162306a36Sopenharmony_ci char *elem; 81262306a36Sopenharmony_ci bool owner_bit; 81362306a36Sopenharmony_ci 81462306a36Sopenharmony_ci elem_info = mlxsw_pci_queue_elem_info_consumer_get(q); 81562306a36Sopenharmony_ci elem = elem_info->elem; 81662306a36Sopenharmony_ci owner_bit = mlxsw_pci_eqe_owner_get(elem); 81762306a36Sopenharmony_ci if (mlxsw_pci_elem_hw_owned(q, owner_bit)) 81862306a36Sopenharmony_ci return NULL; 81962306a36Sopenharmony_ci q->consumer_counter++; 82062306a36Sopenharmony_ci rmb(); /* make sure we read owned bit before the rest of elem */ 82162306a36Sopenharmony_ci return elem; 82262306a36Sopenharmony_ci} 82362306a36Sopenharmony_ci 82462306a36Sopenharmony_cistatic void mlxsw_pci_eq_tasklet(struct tasklet_struct *t) 82562306a36Sopenharmony_ci{ 82662306a36Sopenharmony_ci struct mlxsw_pci_queue *q = from_tasklet(q, t, tasklet); 82762306a36Sopenharmony_ci struct mlxsw_pci *mlxsw_pci = q->pci; 82862306a36Sopenharmony_ci u8 cq_count = mlxsw_pci_cq_count(mlxsw_pci); 82962306a36Sopenharmony_ci unsigned long active_cqns[BITS_TO_LONGS(MLXSW_PCI_CQS_MAX)]; 83062306a36Sopenharmony_ci char *eqe; 83162306a36Sopenharmony_ci u8 cqn; 83262306a36Sopenharmony_ci bool cq_handle = false; 83362306a36Sopenharmony_ci int items = 0; 83462306a36Sopenharmony_ci int credits = q->count >> 1; 83562306a36Sopenharmony_ci 83662306a36Sopenharmony_ci memset(&active_cqns, 0, sizeof(active_cqns)); 83762306a36Sopenharmony_ci 83862306a36Sopenharmony_ci while ((eqe = mlxsw_pci_eq_sw_eqe_get(q))) { 83962306a36Sopenharmony_ci 84062306a36Sopenharmony_ci /* Command interface completion events are always received on 84162306a36Sopenharmony_ci * queue MLXSW_PCI_EQ_ASYNC_NUM (EQ0) and completion events 84262306a36Sopenharmony_ci * are mapped to queue MLXSW_PCI_EQ_COMP_NUM (EQ1). 84362306a36Sopenharmony_ci */ 84462306a36Sopenharmony_ci switch (q->num) { 84562306a36Sopenharmony_ci case MLXSW_PCI_EQ_ASYNC_NUM: 84662306a36Sopenharmony_ci mlxsw_pci_eq_cmd_event(mlxsw_pci, eqe); 84762306a36Sopenharmony_ci q->u.eq.ev_cmd_count++; 84862306a36Sopenharmony_ci break; 84962306a36Sopenharmony_ci case MLXSW_PCI_EQ_COMP_NUM: 85062306a36Sopenharmony_ci cqn = mlxsw_pci_eqe_cqn_get(eqe); 85162306a36Sopenharmony_ci set_bit(cqn, active_cqns); 85262306a36Sopenharmony_ci cq_handle = true; 85362306a36Sopenharmony_ci q->u.eq.ev_comp_count++; 85462306a36Sopenharmony_ci break; 85562306a36Sopenharmony_ci default: 85662306a36Sopenharmony_ci q->u.eq.ev_other_count++; 85762306a36Sopenharmony_ci } 85862306a36Sopenharmony_ci if (++items == credits) 85962306a36Sopenharmony_ci break; 86062306a36Sopenharmony_ci } 86162306a36Sopenharmony_ci if (items) { 86262306a36Sopenharmony_ci mlxsw_pci_queue_doorbell_consumer_ring(mlxsw_pci, q); 86362306a36Sopenharmony_ci mlxsw_pci_queue_doorbell_arm_consumer_ring(mlxsw_pci, q); 86462306a36Sopenharmony_ci } 86562306a36Sopenharmony_ci 86662306a36Sopenharmony_ci if (!cq_handle) 86762306a36Sopenharmony_ci return; 86862306a36Sopenharmony_ci for_each_set_bit(cqn, active_cqns, cq_count) { 86962306a36Sopenharmony_ci q = mlxsw_pci_cq_get(mlxsw_pci, cqn); 87062306a36Sopenharmony_ci mlxsw_pci_queue_tasklet_schedule(q); 87162306a36Sopenharmony_ci } 87262306a36Sopenharmony_ci} 87362306a36Sopenharmony_ci 87462306a36Sopenharmony_cistruct mlxsw_pci_queue_ops { 87562306a36Sopenharmony_ci const char *name; 87662306a36Sopenharmony_ci enum mlxsw_pci_queue_type type; 87762306a36Sopenharmony_ci void (*pre_init)(struct mlxsw_pci *mlxsw_pci, 87862306a36Sopenharmony_ci struct mlxsw_pci_queue *q); 87962306a36Sopenharmony_ci int (*init)(struct mlxsw_pci *mlxsw_pci, char *mbox, 88062306a36Sopenharmony_ci struct mlxsw_pci_queue *q); 88162306a36Sopenharmony_ci void (*fini)(struct mlxsw_pci *mlxsw_pci, 88262306a36Sopenharmony_ci struct mlxsw_pci_queue *q); 88362306a36Sopenharmony_ci void (*tasklet)(struct tasklet_struct *t); 88462306a36Sopenharmony_ci u16 (*elem_count_f)(const struct mlxsw_pci_queue *q); 88562306a36Sopenharmony_ci u8 (*elem_size_f)(const struct mlxsw_pci_queue *q); 88662306a36Sopenharmony_ci u16 elem_count; 88762306a36Sopenharmony_ci u8 elem_size; 88862306a36Sopenharmony_ci}; 88962306a36Sopenharmony_ci 89062306a36Sopenharmony_cistatic const struct mlxsw_pci_queue_ops mlxsw_pci_sdq_ops = { 89162306a36Sopenharmony_ci .type = MLXSW_PCI_QUEUE_TYPE_SDQ, 89262306a36Sopenharmony_ci .init = mlxsw_pci_sdq_init, 89362306a36Sopenharmony_ci .fini = mlxsw_pci_sdq_fini, 89462306a36Sopenharmony_ci .elem_count = MLXSW_PCI_WQE_COUNT, 89562306a36Sopenharmony_ci .elem_size = MLXSW_PCI_WQE_SIZE, 89662306a36Sopenharmony_ci}; 89762306a36Sopenharmony_ci 89862306a36Sopenharmony_cistatic const struct mlxsw_pci_queue_ops mlxsw_pci_rdq_ops = { 89962306a36Sopenharmony_ci .type = MLXSW_PCI_QUEUE_TYPE_RDQ, 90062306a36Sopenharmony_ci .init = mlxsw_pci_rdq_init, 90162306a36Sopenharmony_ci .fini = mlxsw_pci_rdq_fini, 90262306a36Sopenharmony_ci .elem_count = MLXSW_PCI_WQE_COUNT, 90362306a36Sopenharmony_ci .elem_size = MLXSW_PCI_WQE_SIZE 90462306a36Sopenharmony_ci}; 90562306a36Sopenharmony_ci 90662306a36Sopenharmony_cistatic const struct mlxsw_pci_queue_ops mlxsw_pci_cq_ops = { 90762306a36Sopenharmony_ci .type = MLXSW_PCI_QUEUE_TYPE_CQ, 90862306a36Sopenharmony_ci .pre_init = mlxsw_pci_cq_pre_init, 90962306a36Sopenharmony_ci .init = mlxsw_pci_cq_init, 91062306a36Sopenharmony_ci .fini = mlxsw_pci_cq_fini, 91162306a36Sopenharmony_ci .tasklet = mlxsw_pci_cq_tasklet, 91262306a36Sopenharmony_ci .elem_count_f = mlxsw_pci_cq_elem_count, 91362306a36Sopenharmony_ci .elem_size_f = mlxsw_pci_cq_elem_size 91462306a36Sopenharmony_ci}; 91562306a36Sopenharmony_ci 91662306a36Sopenharmony_cistatic const struct mlxsw_pci_queue_ops mlxsw_pci_eq_ops = { 91762306a36Sopenharmony_ci .type = MLXSW_PCI_QUEUE_TYPE_EQ, 91862306a36Sopenharmony_ci .init = mlxsw_pci_eq_init, 91962306a36Sopenharmony_ci .fini = mlxsw_pci_eq_fini, 92062306a36Sopenharmony_ci .tasklet = mlxsw_pci_eq_tasklet, 92162306a36Sopenharmony_ci .elem_count = MLXSW_PCI_EQE_COUNT, 92262306a36Sopenharmony_ci .elem_size = MLXSW_PCI_EQE_SIZE 92362306a36Sopenharmony_ci}; 92462306a36Sopenharmony_ci 92562306a36Sopenharmony_cistatic int mlxsw_pci_queue_init(struct mlxsw_pci *mlxsw_pci, char *mbox, 92662306a36Sopenharmony_ci const struct mlxsw_pci_queue_ops *q_ops, 92762306a36Sopenharmony_ci struct mlxsw_pci_queue *q, u8 q_num) 92862306a36Sopenharmony_ci{ 92962306a36Sopenharmony_ci struct mlxsw_pci_mem_item *mem_item = &q->mem_item; 93062306a36Sopenharmony_ci int i; 93162306a36Sopenharmony_ci int err; 93262306a36Sopenharmony_ci 93362306a36Sopenharmony_ci q->num = q_num; 93462306a36Sopenharmony_ci if (q_ops->pre_init) 93562306a36Sopenharmony_ci q_ops->pre_init(mlxsw_pci, q); 93662306a36Sopenharmony_ci 93762306a36Sopenharmony_ci spin_lock_init(&q->lock); 93862306a36Sopenharmony_ci q->count = q_ops->elem_count_f ? q_ops->elem_count_f(q) : 93962306a36Sopenharmony_ci q_ops->elem_count; 94062306a36Sopenharmony_ci q->elem_size = q_ops->elem_size_f ? q_ops->elem_size_f(q) : 94162306a36Sopenharmony_ci q_ops->elem_size; 94262306a36Sopenharmony_ci q->type = q_ops->type; 94362306a36Sopenharmony_ci q->pci = mlxsw_pci; 94462306a36Sopenharmony_ci 94562306a36Sopenharmony_ci if (q_ops->tasklet) 94662306a36Sopenharmony_ci tasklet_setup(&q->tasklet, q_ops->tasklet); 94762306a36Sopenharmony_ci 94862306a36Sopenharmony_ci mem_item->size = MLXSW_PCI_AQ_SIZE; 94962306a36Sopenharmony_ci mem_item->buf = dma_alloc_coherent(&mlxsw_pci->pdev->dev, 95062306a36Sopenharmony_ci mem_item->size, &mem_item->mapaddr, 95162306a36Sopenharmony_ci GFP_KERNEL); 95262306a36Sopenharmony_ci if (!mem_item->buf) 95362306a36Sopenharmony_ci return -ENOMEM; 95462306a36Sopenharmony_ci 95562306a36Sopenharmony_ci q->elem_info = kcalloc(q->count, sizeof(*q->elem_info), GFP_KERNEL); 95662306a36Sopenharmony_ci if (!q->elem_info) { 95762306a36Sopenharmony_ci err = -ENOMEM; 95862306a36Sopenharmony_ci goto err_elem_info_alloc; 95962306a36Sopenharmony_ci } 96062306a36Sopenharmony_ci 96162306a36Sopenharmony_ci /* Initialize dma mapped elements info elem_info for 96262306a36Sopenharmony_ci * future easy access. 96362306a36Sopenharmony_ci */ 96462306a36Sopenharmony_ci for (i = 0; i < q->count; i++) { 96562306a36Sopenharmony_ci struct mlxsw_pci_queue_elem_info *elem_info; 96662306a36Sopenharmony_ci 96762306a36Sopenharmony_ci elem_info = mlxsw_pci_queue_elem_info_get(q, i); 96862306a36Sopenharmony_ci elem_info->elem = 96962306a36Sopenharmony_ci __mlxsw_pci_queue_elem_get(q, q->elem_size, i); 97062306a36Sopenharmony_ci } 97162306a36Sopenharmony_ci 97262306a36Sopenharmony_ci mlxsw_cmd_mbox_zero(mbox); 97362306a36Sopenharmony_ci err = q_ops->init(mlxsw_pci, mbox, q); 97462306a36Sopenharmony_ci if (err) 97562306a36Sopenharmony_ci goto err_q_ops_init; 97662306a36Sopenharmony_ci return 0; 97762306a36Sopenharmony_ci 97862306a36Sopenharmony_cierr_q_ops_init: 97962306a36Sopenharmony_ci kfree(q->elem_info); 98062306a36Sopenharmony_cierr_elem_info_alloc: 98162306a36Sopenharmony_ci dma_free_coherent(&mlxsw_pci->pdev->dev, mem_item->size, 98262306a36Sopenharmony_ci mem_item->buf, mem_item->mapaddr); 98362306a36Sopenharmony_ci return err; 98462306a36Sopenharmony_ci} 98562306a36Sopenharmony_ci 98662306a36Sopenharmony_cistatic void mlxsw_pci_queue_fini(struct mlxsw_pci *mlxsw_pci, 98762306a36Sopenharmony_ci const struct mlxsw_pci_queue_ops *q_ops, 98862306a36Sopenharmony_ci struct mlxsw_pci_queue *q) 98962306a36Sopenharmony_ci{ 99062306a36Sopenharmony_ci struct mlxsw_pci_mem_item *mem_item = &q->mem_item; 99162306a36Sopenharmony_ci 99262306a36Sopenharmony_ci q_ops->fini(mlxsw_pci, q); 99362306a36Sopenharmony_ci kfree(q->elem_info); 99462306a36Sopenharmony_ci dma_free_coherent(&mlxsw_pci->pdev->dev, mem_item->size, 99562306a36Sopenharmony_ci mem_item->buf, mem_item->mapaddr); 99662306a36Sopenharmony_ci} 99762306a36Sopenharmony_ci 99862306a36Sopenharmony_cistatic int mlxsw_pci_queue_group_init(struct mlxsw_pci *mlxsw_pci, char *mbox, 99962306a36Sopenharmony_ci const struct mlxsw_pci_queue_ops *q_ops, 100062306a36Sopenharmony_ci u8 num_qs) 100162306a36Sopenharmony_ci{ 100262306a36Sopenharmony_ci struct mlxsw_pci_queue_type_group *queue_group; 100362306a36Sopenharmony_ci int i; 100462306a36Sopenharmony_ci int err; 100562306a36Sopenharmony_ci 100662306a36Sopenharmony_ci queue_group = mlxsw_pci_queue_type_group_get(mlxsw_pci, q_ops->type); 100762306a36Sopenharmony_ci queue_group->q = kcalloc(num_qs, sizeof(*queue_group->q), GFP_KERNEL); 100862306a36Sopenharmony_ci if (!queue_group->q) 100962306a36Sopenharmony_ci return -ENOMEM; 101062306a36Sopenharmony_ci 101162306a36Sopenharmony_ci for (i = 0; i < num_qs; i++) { 101262306a36Sopenharmony_ci err = mlxsw_pci_queue_init(mlxsw_pci, mbox, q_ops, 101362306a36Sopenharmony_ci &queue_group->q[i], i); 101462306a36Sopenharmony_ci if (err) 101562306a36Sopenharmony_ci goto err_queue_init; 101662306a36Sopenharmony_ci } 101762306a36Sopenharmony_ci queue_group->count = num_qs; 101862306a36Sopenharmony_ci 101962306a36Sopenharmony_ci return 0; 102062306a36Sopenharmony_ci 102162306a36Sopenharmony_cierr_queue_init: 102262306a36Sopenharmony_ci for (i--; i >= 0; i--) 102362306a36Sopenharmony_ci mlxsw_pci_queue_fini(mlxsw_pci, q_ops, &queue_group->q[i]); 102462306a36Sopenharmony_ci kfree(queue_group->q); 102562306a36Sopenharmony_ci return err; 102662306a36Sopenharmony_ci} 102762306a36Sopenharmony_ci 102862306a36Sopenharmony_cistatic void mlxsw_pci_queue_group_fini(struct mlxsw_pci *mlxsw_pci, 102962306a36Sopenharmony_ci const struct mlxsw_pci_queue_ops *q_ops) 103062306a36Sopenharmony_ci{ 103162306a36Sopenharmony_ci struct mlxsw_pci_queue_type_group *queue_group; 103262306a36Sopenharmony_ci int i; 103362306a36Sopenharmony_ci 103462306a36Sopenharmony_ci queue_group = mlxsw_pci_queue_type_group_get(mlxsw_pci, q_ops->type); 103562306a36Sopenharmony_ci for (i = 0; i < queue_group->count; i++) 103662306a36Sopenharmony_ci mlxsw_pci_queue_fini(mlxsw_pci, q_ops, &queue_group->q[i]); 103762306a36Sopenharmony_ci kfree(queue_group->q); 103862306a36Sopenharmony_ci} 103962306a36Sopenharmony_ci 104062306a36Sopenharmony_cistatic int mlxsw_pci_aqs_init(struct mlxsw_pci *mlxsw_pci, char *mbox) 104162306a36Sopenharmony_ci{ 104262306a36Sopenharmony_ci struct pci_dev *pdev = mlxsw_pci->pdev; 104362306a36Sopenharmony_ci u8 num_sdqs; 104462306a36Sopenharmony_ci u8 sdq_log2sz; 104562306a36Sopenharmony_ci u8 num_rdqs; 104662306a36Sopenharmony_ci u8 rdq_log2sz; 104762306a36Sopenharmony_ci u8 num_cqs; 104862306a36Sopenharmony_ci u8 cq_log2sz; 104962306a36Sopenharmony_ci u8 cqv2_log2sz; 105062306a36Sopenharmony_ci u8 num_eqs; 105162306a36Sopenharmony_ci u8 eq_log2sz; 105262306a36Sopenharmony_ci int err; 105362306a36Sopenharmony_ci 105462306a36Sopenharmony_ci mlxsw_cmd_mbox_zero(mbox); 105562306a36Sopenharmony_ci err = mlxsw_cmd_query_aq_cap(mlxsw_pci->core, mbox); 105662306a36Sopenharmony_ci if (err) 105762306a36Sopenharmony_ci return err; 105862306a36Sopenharmony_ci 105962306a36Sopenharmony_ci num_sdqs = mlxsw_cmd_mbox_query_aq_cap_max_num_sdqs_get(mbox); 106062306a36Sopenharmony_ci sdq_log2sz = mlxsw_cmd_mbox_query_aq_cap_log_max_sdq_sz_get(mbox); 106162306a36Sopenharmony_ci num_rdqs = mlxsw_cmd_mbox_query_aq_cap_max_num_rdqs_get(mbox); 106262306a36Sopenharmony_ci rdq_log2sz = mlxsw_cmd_mbox_query_aq_cap_log_max_rdq_sz_get(mbox); 106362306a36Sopenharmony_ci num_cqs = mlxsw_cmd_mbox_query_aq_cap_max_num_cqs_get(mbox); 106462306a36Sopenharmony_ci cq_log2sz = mlxsw_cmd_mbox_query_aq_cap_log_max_cq_sz_get(mbox); 106562306a36Sopenharmony_ci cqv2_log2sz = mlxsw_cmd_mbox_query_aq_cap_log_max_cqv2_sz_get(mbox); 106662306a36Sopenharmony_ci num_eqs = mlxsw_cmd_mbox_query_aq_cap_max_num_eqs_get(mbox); 106762306a36Sopenharmony_ci eq_log2sz = mlxsw_cmd_mbox_query_aq_cap_log_max_eq_sz_get(mbox); 106862306a36Sopenharmony_ci 106962306a36Sopenharmony_ci if (num_sdqs + num_rdqs > num_cqs || 107062306a36Sopenharmony_ci num_sdqs < MLXSW_PCI_SDQS_MIN || 107162306a36Sopenharmony_ci num_cqs > MLXSW_PCI_CQS_MAX || num_eqs != MLXSW_PCI_EQS_COUNT) { 107262306a36Sopenharmony_ci dev_err(&pdev->dev, "Unsupported number of queues\n"); 107362306a36Sopenharmony_ci return -EINVAL; 107462306a36Sopenharmony_ci } 107562306a36Sopenharmony_ci 107662306a36Sopenharmony_ci if ((1 << sdq_log2sz != MLXSW_PCI_WQE_COUNT) || 107762306a36Sopenharmony_ci (1 << rdq_log2sz != MLXSW_PCI_WQE_COUNT) || 107862306a36Sopenharmony_ci (1 << cq_log2sz != MLXSW_PCI_CQE01_COUNT) || 107962306a36Sopenharmony_ci (mlxsw_pci->max_cqe_ver == MLXSW_PCI_CQE_V2 && 108062306a36Sopenharmony_ci (1 << cqv2_log2sz != MLXSW_PCI_CQE2_COUNT)) || 108162306a36Sopenharmony_ci (1 << eq_log2sz != MLXSW_PCI_EQE_COUNT)) { 108262306a36Sopenharmony_ci dev_err(&pdev->dev, "Unsupported number of async queue descriptors\n"); 108362306a36Sopenharmony_ci return -EINVAL; 108462306a36Sopenharmony_ci } 108562306a36Sopenharmony_ci 108662306a36Sopenharmony_ci mlxsw_pci->num_sdq_cqs = num_sdqs; 108762306a36Sopenharmony_ci 108862306a36Sopenharmony_ci err = mlxsw_pci_queue_group_init(mlxsw_pci, mbox, &mlxsw_pci_eq_ops, 108962306a36Sopenharmony_ci num_eqs); 109062306a36Sopenharmony_ci if (err) { 109162306a36Sopenharmony_ci dev_err(&pdev->dev, "Failed to initialize event queues\n"); 109262306a36Sopenharmony_ci return err; 109362306a36Sopenharmony_ci } 109462306a36Sopenharmony_ci 109562306a36Sopenharmony_ci err = mlxsw_pci_queue_group_init(mlxsw_pci, mbox, &mlxsw_pci_cq_ops, 109662306a36Sopenharmony_ci num_cqs); 109762306a36Sopenharmony_ci if (err) { 109862306a36Sopenharmony_ci dev_err(&pdev->dev, "Failed to initialize completion queues\n"); 109962306a36Sopenharmony_ci goto err_cqs_init; 110062306a36Sopenharmony_ci } 110162306a36Sopenharmony_ci 110262306a36Sopenharmony_ci err = mlxsw_pci_queue_group_init(mlxsw_pci, mbox, &mlxsw_pci_sdq_ops, 110362306a36Sopenharmony_ci num_sdqs); 110462306a36Sopenharmony_ci if (err) { 110562306a36Sopenharmony_ci dev_err(&pdev->dev, "Failed to initialize send descriptor queues\n"); 110662306a36Sopenharmony_ci goto err_sdqs_init; 110762306a36Sopenharmony_ci } 110862306a36Sopenharmony_ci 110962306a36Sopenharmony_ci err = mlxsw_pci_queue_group_init(mlxsw_pci, mbox, &mlxsw_pci_rdq_ops, 111062306a36Sopenharmony_ci num_rdqs); 111162306a36Sopenharmony_ci if (err) { 111262306a36Sopenharmony_ci dev_err(&pdev->dev, "Failed to initialize receive descriptor queues\n"); 111362306a36Sopenharmony_ci goto err_rdqs_init; 111462306a36Sopenharmony_ci } 111562306a36Sopenharmony_ci 111662306a36Sopenharmony_ci /* We have to poll in command interface until queues are initialized */ 111762306a36Sopenharmony_ci mlxsw_pci->cmd.nopoll = true; 111862306a36Sopenharmony_ci return 0; 111962306a36Sopenharmony_ci 112062306a36Sopenharmony_cierr_rdqs_init: 112162306a36Sopenharmony_ci mlxsw_pci_queue_group_fini(mlxsw_pci, &mlxsw_pci_sdq_ops); 112262306a36Sopenharmony_cierr_sdqs_init: 112362306a36Sopenharmony_ci mlxsw_pci_queue_group_fini(mlxsw_pci, &mlxsw_pci_cq_ops); 112462306a36Sopenharmony_cierr_cqs_init: 112562306a36Sopenharmony_ci mlxsw_pci_queue_group_fini(mlxsw_pci, &mlxsw_pci_eq_ops); 112662306a36Sopenharmony_ci return err; 112762306a36Sopenharmony_ci} 112862306a36Sopenharmony_ci 112962306a36Sopenharmony_cistatic void mlxsw_pci_aqs_fini(struct mlxsw_pci *mlxsw_pci) 113062306a36Sopenharmony_ci{ 113162306a36Sopenharmony_ci mlxsw_pci->cmd.nopoll = false; 113262306a36Sopenharmony_ci mlxsw_pci_queue_group_fini(mlxsw_pci, &mlxsw_pci_rdq_ops); 113362306a36Sopenharmony_ci mlxsw_pci_queue_group_fini(mlxsw_pci, &mlxsw_pci_sdq_ops); 113462306a36Sopenharmony_ci mlxsw_pci_queue_group_fini(mlxsw_pci, &mlxsw_pci_cq_ops); 113562306a36Sopenharmony_ci mlxsw_pci_queue_group_fini(mlxsw_pci, &mlxsw_pci_eq_ops); 113662306a36Sopenharmony_ci} 113762306a36Sopenharmony_ci 113862306a36Sopenharmony_cistatic void 113962306a36Sopenharmony_cimlxsw_pci_config_profile_swid_config(struct mlxsw_pci *mlxsw_pci, 114062306a36Sopenharmony_ci char *mbox, int index, 114162306a36Sopenharmony_ci const struct mlxsw_swid_config *swid) 114262306a36Sopenharmony_ci{ 114362306a36Sopenharmony_ci u8 mask = 0; 114462306a36Sopenharmony_ci 114562306a36Sopenharmony_ci if (swid->used_type) { 114662306a36Sopenharmony_ci mlxsw_cmd_mbox_config_profile_swid_config_type_set( 114762306a36Sopenharmony_ci mbox, index, swid->type); 114862306a36Sopenharmony_ci mask |= 1; 114962306a36Sopenharmony_ci } 115062306a36Sopenharmony_ci if (swid->used_properties) { 115162306a36Sopenharmony_ci mlxsw_cmd_mbox_config_profile_swid_config_properties_set( 115262306a36Sopenharmony_ci mbox, index, swid->properties); 115362306a36Sopenharmony_ci mask |= 2; 115462306a36Sopenharmony_ci } 115562306a36Sopenharmony_ci mlxsw_cmd_mbox_config_profile_swid_config_mask_set(mbox, index, mask); 115662306a36Sopenharmony_ci} 115762306a36Sopenharmony_ci 115862306a36Sopenharmony_cistatic int 115962306a36Sopenharmony_cimlxsw_pci_profile_get_kvd_sizes(const struct mlxsw_pci *mlxsw_pci, 116062306a36Sopenharmony_ci const struct mlxsw_config_profile *profile, 116162306a36Sopenharmony_ci struct mlxsw_res *res) 116262306a36Sopenharmony_ci{ 116362306a36Sopenharmony_ci u64 single_size, double_size, linear_size; 116462306a36Sopenharmony_ci int err; 116562306a36Sopenharmony_ci 116662306a36Sopenharmony_ci err = mlxsw_core_kvd_sizes_get(mlxsw_pci->core, profile, 116762306a36Sopenharmony_ci &single_size, &double_size, 116862306a36Sopenharmony_ci &linear_size); 116962306a36Sopenharmony_ci if (err) 117062306a36Sopenharmony_ci return err; 117162306a36Sopenharmony_ci 117262306a36Sopenharmony_ci MLXSW_RES_SET(res, KVD_SINGLE_SIZE, single_size); 117362306a36Sopenharmony_ci MLXSW_RES_SET(res, KVD_DOUBLE_SIZE, double_size); 117462306a36Sopenharmony_ci MLXSW_RES_SET(res, KVD_LINEAR_SIZE, linear_size); 117562306a36Sopenharmony_ci 117662306a36Sopenharmony_ci return 0; 117762306a36Sopenharmony_ci} 117862306a36Sopenharmony_ci 117962306a36Sopenharmony_cistatic int mlxsw_pci_config_profile(struct mlxsw_pci *mlxsw_pci, char *mbox, 118062306a36Sopenharmony_ci const struct mlxsw_config_profile *profile, 118162306a36Sopenharmony_ci struct mlxsw_res *res) 118262306a36Sopenharmony_ci{ 118362306a36Sopenharmony_ci int i; 118462306a36Sopenharmony_ci int err; 118562306a36Sopenharmony_ci 118662306a36Sopenharmony_ci mlxsw_cmd_mbox_zero(mbox); 118762306a36Sopenharmony_ci 118862306a36Sopenharmony_ci if (profile->used_max_vepa_channels) { 118962306a36Sopenharmony_ci mlxsw_cmd_mbox_config_profile_set_max_vepa_channels_set( 119062306a36Sopenharmony_ci mbox, 1); 119162306a36Sopenharmony_ci mlxsw_cmd_mbox_config_profile_max_vepa_channels_set( 119262306a36Sopenharmony_ci mbox, profile->max_vepa_channels); 119362306a36Sopenharmony_ci } 119462306a36Sopenharmony_ci if (profile->used_max_lag) { 119562306a36Sopenharmony_ci mlxsw_cmd_mbox_config_profile_set_max_lag_set(mbox, 1); 119662306a36Sopenharmony_ci mlxsw_cmd_mbox_config_profile_max_lag_set(mbox, 119762306a36Sopenharmony_ci profile->max_lag); 119862306a36Sopenharmony_ci } 119962306a36Sopenharmony_ci if (profile->used_max_mid) { 120062306a36Sopenharmony_ci mlxsw_cmd_mbox_config_profile_set_max_mid_set( 120162306a36Sopenharmony_ci mbox, 1); 120262306a36Sopenharmony_ci mlxsw_cmd_mbox_config_profile_max_mid_set( 120362306a36Sopenharmony_ci mbox, profile->max_mid); 120462306a36Sopenharmony_ci } 120562306a36Sopenharmony_ci if (profile->used_max_pgt) { 120662306a36Sopenharmony_ci mlxsw_cmd_mbox_config_profile_set_max_pgt_set( 120762306a36Sopenharmony_ci mbox, 1); 120862306a36Sopenharmony_ci mlxsw_cmd_mbox_config_profile_max_pgt_set( 120962306a36Sopenharmony_ci mbox, profile->max_pgt); 121062306a36Sopenharmony_ci } 121162306a36Sopenharmony_ci if (profile->used_max_system_port) { 121262306a36Sopenharmony_ci mlxsw_cmd_mbox_config_profile_set_max_system_port_set( 121362306a36Sopenharmony_ci mbox, 1); 121462306a36Sopenharmony_ci mlxsw_cmd_mbox_config_profile_max_system_port_set( 121562306a36Sopenharmony_ci mbox, profile->max_system_port); 121662306a36Sopenharmony_ci } 121762306a36Sopenharmony_ci if (profile->used_max_vlan_groups) { 121862306a36Sopenharmony_ci mlxsw_cmd_mbox_config_profile_set_max_vlan_groups_set( 121962306a36Sopenharmony_ci mbox, 1); 122062306a36Sopenharmony_ci mlxsw_cmd_mbox_config_profile_max_vlan_groups_set( 122162306a36Sopenharmony_ci mbox, profile->max_vlan_groups); 122262306a36Sopenharmony_ci } 122362306a36Sopenharmony_ci if (profile->used_max_regions) { 122462306a36Sopenharmony_ci mlxsw_cmd_mbox_config_profile_set_max_regions_set( 122562306a36Sopenharmony_ci mbox, 1); 122662306a36Sopenharmony_ci mlxsw_cmd_mbox_config_profile_max_regions_set( 122762306a36Sopenharmony_ci mbox, profile->max_regions); 122862306a36Sopenharmony_ci } 122962306a36Sopenharmony_ci if (profile->used_flood_tables) { 123062306a36Sopenharmony_ci mlxsw_cmd_mbox_config_profile_set_flood_tables_set( 123162306a36Sopenharmony_ci mbox, 1); 123262306a36Sopenharmony_ci mlxsw_cmd_mbox_config_profile_max_flood_tables_set( 123362306a36Sopenharmony_ci mbox, profile->max_flood_tables); 123462306a36Sopenharmony_ci mlxsw_cmd_mbox_config_profile_max_vid_flood_tables_set( 123562306a36Sopenharmony_ci mbox, profile->max_vid_flood_tables); 123662306a36Sopenharmony_ci mlxsw_cmd_mbox_config_profile_max_fid_offset_flood_tables_set( 123762306a36Sopenharmony_ci mbox, profile->max_fid_offset_flood_tables); 123862306a36Sopenharmony_ci mlxsw_cmd_mbox_config_profile_fid_offset_flood_table_size_set( 123962306a36Sopenharmony_ci mbox, profile->fid_offset_flood_table_size); 124062306a36Sopenharmony_ci mlxsw_cmd_mbox_config_profile_max_fid_flood_tables_set( 124162306a36Sopenharmony_ci mbox, profile->max_fid_flood_tables); 124262306a36Sopenharmony_ci mlxsw_cmd_mbox_config_profile_fid_flood_table_size_set( 124362306a36Sopenharmony_ci mbox, profile->fid_flood_table_size); 124462306a36Sopenharmony_ci } 124562306a36Sopenharmony_ci if (profile->used_flood_mode) { 124662306a36Sopenharmony_ci mlxsw_cmd_mbox_config_profile_set_flood_mode_set( 124762306a36Sopenharmony_ci mbox, 1); 124862306a36Sopenharmony_ci mlxsw_cmd_mbox_config_profile_flood_mode_set( 124962306a36Sopenharmony_ci mbox, profile->flood_mode); 125062306a36Sopenharmony_ci } 125162306a36Sopenharmony_ci if (profile->used_max_ib_mc) { 125262306a36Sopenharmony_ci mlxsw_cmd_mbox_config_profile_set_max_ib_mc_set( 125362306a36Sopenharmony_ci mbox, 1); 125462306a36Sopenharmony_ci mlxsw_cmd_mbox_config_profile_max_ib_mc_set( 125562306a36Sopenharmony_ci mbox, profile->max_ib_mc); 125662306a36Sopenharmony_ci } 125762306a36Sopenharmony_ci if (profile->used_max_pkey) { 125862306a36Sopenharmony_ci mlxsw_cmd_mbox_config_profile_set_max_pkey_set( 125962306a36Sopenharmony_ci mbox, 1); 126062306a36Sopenharmony_ci mlxsw_cmd_mbox_config_profile_max_pkey_set( 126162306a36Sopenharmony_ci mbox, profile->max_pkey); 126262306a36Sopenharmony_ci } 126362306a36Sopenharmony_ci if (profile->used_ar_sec) { 126462306a36Sopenharmony_ci mlxsw_cmd_mbox_config_profile_set_ar_sec_set( 126562306a36Sopenharmony_ci mbox, 1); 126662306a36Sopenharmony_ci mlxsw_cmd_mbox_config_profile_ar_sec_set( 126762306a36Sopenharmony_ci mbox, profile->ar_sec); 126862306a36Sopenharmony_ci } 126962306a36Sopenharmony_ci if (profile->used_adaptive_routing_group_cap) { 127062306a36Sopenharmony_ci mlxsw_cmd_mbox_config_profile_set_adaptive_routing_group_cap_set( 127162306a36Sopenharmony_ci mbox, 1); 127262306a36Sopenharmony_ci mlxsw_cmd_mbox_config_profile_adaptive_routing_group_cap_set( 127362306a36Sopenharmony_ci mbox, profile->adaptive_routing_group_cap); 127462306a36Sopenharmony_ci } 127562306a36Sopenharmony_ci if (profile->used_ubridge) { 127662306a36Sopenharmony_ci mlxsw_cmd_mbox_config_profile_set_ubridge_set(mbox, 1); 127762306a36Sopenharmony_ci mlxsw_cmd_mbox_config_profile_ubridge_set(mbox, 127862306a36Sopenharmony_ci profile->ubridge); 127962306a36Sopenharmony_ci } 128062306a36Sopenharmony_ci if (profile->used_kvd_sizes && MLXSW_RES_VALID(res, KVD_SIZE)) { 128162306a36Sopenharmony_ci err = mlxsw_pci_profile_get_kvd_sizes(mlxsw_pci, profile, res); 128262306a36Sopenharmony_ci if (err) 128362306a36Sopenharmony_ci return err; 128462306a36Sopenharmony_ci 128562306a36Sopenharmony_ci mlxsw_cmd_mbox_config_profile_set_kvd_linear_size_set(mbox, 1); 128662306a36Sopenharmony_ci mlxsw_cmd_mbox_config_profile_kvd_linear_size_set(mbox, 128762306a36Sopenharmony_ci MLXSW_RES_GET(res, KVD_LINEAR_SIZE)); 128862306a36Sopenharmony_ci mlxsw_cmd_mbox_config_profile_set_kvd_hash_single_size_set(mbox, 128962306a36Sopenharmony_ci 1); 129062306a36Sopenharmony_ci mlxsw_cmd_mbox_config_profile_kvd_hash_single_size_set(mbox, 129162306a36Sopenharmony_ci MLXSW_RES_GET(res, KVD_SINGLE_SIZE)); 129262306a36Sopenharmony_ci mlxsw_cmd_mbox_config_profile_set_kvd_hash_double_size_set( 129362306a36Sopenharmony_ci mbox, 1); 129462306a36Sopenharmony_ci mlxsw_cmd_mbox_config_profile_kvd_hash_double_size_set(mbox, 129562306a36Sopenharmony_ci MLXSW_RES_GET(res, KVD_DOUBLE_SIZE)); 129662306a36Sopenharmony_ci } 129762306a36Sopenharmony_ci 129862306a36Sopenharmony_ci for (i = 0; i < MLXSW_CONFIG_PROFILE_SWID_COUNT; i++) 129962306a36Sopenharmony_ci mlxsw_pci_config_profile_swid_config(mlxsw_pci, mbox, i, 130062306a36Sopenharmony_ci &profile->swid_config[i]); 130162306a36Sopenharmony_ci 130262306a36Sopenharmony_ci if (mlxsw_pci->max_cqe_ver > MLXSW_PCI_CQE_V0) { 130362306a36Sopenharmony_ci mlxsw_cmd_mbox_config_profile_set_cqe_version_set(mbox, 1); 130462306a36Sopenharmony_ci mlxsw_cmd_mbox_config_profile_cqe_version_set(mbox, 1); 130562306a36Sopenharmony_ci } 130662306a36Sopenharmony_ci 130762306a36Sopenharmony_ci if (profile->used_cqe_time_stamp_type) { 130862306a36Sopenharmony_ci mlxsw_cmd_mbox_config_profile_set_cqe_time_stamp_type_set(mbox, 130962306a36Sopenharmony_ci 1); 131062306a36Sopenharmony_ci mlxsw_cmd_mbox_config_profile_cqe_time_stamp_type_set(mbox, 131162306a36Sopenharmony_ci profile->cqe_time_stamp_type); 131262306a36Sopenharmony_ci } 131362306a36Sopenharmony_ci 131462306a36Sopenharmony_ci return mlxsw_cmd_config_profile_set(mlxsw_pci->core, mbox); 131562306a36Sopenharmony_ci} 131662306a36Sopenharmony_ci 131762306a36Sopenharmony_cistatic int mlxsw_pci_boardinfo(struct mlxsw_pci *mlxsw_pci, char *mbox) 131862306a36Sopenharmony_ci{ 131962306a36Sopenharmony_ci struct mlxsw_bus_info *bus_info = &mlxsw_pci->bus_info; 132062306a36Sopenharmony_ci int err; 132162306a36Sopenharmony_ci 132262306a36Sopenharmony_ci mlxsw_cmd_mbox_zero(mbox); 132362306a36Sopenharmony_ci err = mlxsw_cmd_boardinfo(mlxsw_pci->core, mbox); 132462306a36Sopenharmony_ci if (err) 132562306a36Sopenharmony_ci return err; 132662306a36Sopenharmony_ci mlxsw_cmd_mbox_boardinfo_vsd_memcpy_from(mbox, bus_info->vsd); 132762306a36Sopenharmony_ci mlxsw_cmd_mbox_boardinfo_psid_memcpy_from(mbox, bus_info->psid); 132862306a36Sopenharmony_ci return 0; 132962306a36Sopenharmony_ci} 133062306a36Sopenharmony_ci 133162306a36Sopenharmony_cistatic int mlxsw_pci_fw_area_init(struct mlxsw_pci *mlxsw_pci, char *mbox, 133262306a36Sopenharmony_ci u16 num_pages) 133362306a36Sopenharmony_ci{ 133462306a36Sopenharmony_ci struct mlxsw_pci_mem_item *mem_item; 133562306a36Sopenharmony_ci int nent = 0; 133662306a36Sopenharmony_ci int i; 133762306a36Sopenharmony_ci int err; 133862306a36Sopenharmony_ci 133962306a36Sopenharmony_ci mlxsw_pci->fw_area.items = kcalloc(num_pages, sizeof(*mem_item), 134062306a36Sopenharmony_ci GFP_KERNEL); 134162306a36Sopenharmony_ci if (!mlxsw_pci->fw_area.items) 134262306a36Sopenharmony_ci return -ENOMEM; 134362306a36Sopenharmony_ci mlxsw_pci->fw_area.count = num_pages; 134462306a36Sopenharmony_ci 134562306a36Sopenharmony_ci mlxsw_cmd_mbox_zero(mbox); 134662306a36Sopenharmony_ci for (i = 0; i < num_pages; i++) { 134762306a36Sopenharmony_ci mem_item = &mlxsw_pci->fw_area.items[i]; 134862306a36Sopenharmony_ci 134962306a36Sopenharmony_ci mem_item->size = MLXSW_PCI_PAGE_SIZE; 135062306a36Sopenharmony_ci mem_item->buf = dma_alloc_coherent(&mlxsw_pci->pdev->dev, 135162306a36Sopenharmony_ci mem_item->size, 135262306a36Sopenharmony_ci &mem_item->mapaddr, GFP_KERNEL); 135362306a36Sopenharmony_ci if (!mem_item->buf) { 135462306a36Sopenharmony_ci err = -ENOMEM; 135562306a36Sopenharmony_ci goto err_alloc; 135662306a36Sopenharmony_ci } 135762306a36Sopenharmony_ci mlxsw_cmd_mbox_map_fa_pa_set(mbox, nent, mem_item->mapaddr); 135862306a36Sopenharmony_ci mlxsw_cmd_mbox_map_fa_log2size_set(mbox, nent, 0); /* 1 page */ 135962306a36Sopenharmony_ci if (++nent == MLXSW_CMD_MAP_FA_VPM_ENTRIES_MAX) { 136062306a36Sopenharmony_ci err = mlxsw_cmd_map_fa(mlxsw_pci->core, mbox, nent); 136162306a36Sopenharmony_ci if (err) 136262306a36Sopenharmony_ci goto err_cmd_map_fa; 136362306a36Sopenharmony_ci nent = 0; 136462306a36Sopenharmony_ci mlxsw_cmd_mbox_zero(mbox); 136562306a36Sopenharmony_ci } 136662306a36Sopenharmony_ci } 136762306a36Sopenharmony_ci 136862306a36Sopenharmony_ci if (nent) { 136962306a36Sopenharmony_ci err = mlxsw_cmd_map_fa(mlxsw_pci->core, mbox, nent); 137062306a36Sopenharmony_ci if (err) 137162306a36Sopenharmony_ci goto err_cmd_map_fa; 137262306a36Sopenharmony_ci } 137362306a36Sopenharmony_ci 137462306a36Sopenharmony_ci return 0; 137562306a36Sopenharmony_ci 137662306a36Sopenharmony_cierr_cmd_map_fa: 137762306a36Sopenharmony_cierr_alloc: 137862306a36Sopenharmony_ci for (i--; i >= 0; i--) { 137962306a36Sopenharmony_ci mem_item = &mlxsw_pci->fw_area.items[i]; 138062306a36Sopenharmony_ci 138162306a36Sopenharmony_ci dma_free_coherent(&mlxsw_pci->pdev->dev, mem_item->size, 138262306a36Sopenharmony_ci mem_item->buf, mem_item->mapaddr); 138362306a36Sopenharmony_ci } 138462306a36Sopenharmony_ci kfree(mlxsw_pci->fw_area.items); 138562306a36Sopenharmony_ci return err; 138662306a36Sopenharmony_ci} 138762306a36Sopenharmony_ci 138862306a36Sopenharmony_cistatic void mlxsw_pci_fw_area_fini(struct mlxsw_pci *mlxsw_pci) 138962306a36Sopenharmony_ci{ 139062306a36Sopenharmony_ci struct mlxsw_pci_mem_item *mem_item; 139162306a36Sopenharmony_ci int i; 139262306a36Sopenharmony_ci 139362306a36Sopenharmony_ci mlxsw_cmd_unmap_fa(mlxsw_pci->core); 139462306a36Sopenharmony_ci 139562306a36Sopenharmony_ci for (i = 0; i < mlxsw_pci->fw_area.count; i++) { 139662306a36Sopenharmony_ci mem_item = &mlxsw_pci->fw_area.items[i]; 139762306a36Sopenharmony_ci 139862306a36Sopenharmony_ci dma_free_coherent(&mlxsw_pci->pdev->dev, mem_item->size, 139962306a36Sopenharmony_ci mem_item->buf, mem_item->mapaddr); 140062306a36Sopenharmony_ci } 140162306a36Sopenharmony_ci kfree(mlxsw_pci->fw_area.items); 140262306a36Sopenharmony_ci} 140362306a36Sopenharmony_ci 140462306a36Sopenharmony_cistatic irqreturn_t mlxsw_pci_eq_irq_handler(int irq, void *dev_id) 140562306a36Sopenharmony_ci{ 140662306a36Sopenharmony_ci struct mlxsw_pci *mlxsw_pci = dev_id; 140762306a36Sopenharmony_ci struct mlxsw_pci_queue *q; 140862306a36Sopenharmony_ci int i; 140962306a36Sopenharmony_ci 141062306a36Sopenharmony_ci for (i = 0; i < MLXSW_PCI_EQS_COUNT; i++) { 141162306a36Sopenharmony_ci q = mlxsw_pci_eq_get(mlxsw_pci, i); 141262306a36Sopenharmony_ci mlxsw_pci_queue_tasklet_schedule(q); 141362306a36Sopenharmony_ci } 141462306a36Sopenharmony_ci return IRQ_HANDLED; 141562306a36Sopenharmony_ci} 141662306a36Sopenharmony_ci 141762306a36Sopenharmony_cistatic int mlxsw_pci_mbox_alloc(struct mlxsw_pci *mlxsw_pci, 141862306a36Sopenharmony_ci struct mlxsw_pci_mem_item *mbox) 141962306a36Sopenharmony_ci{ 142062306a36Sopenharmony_ci struct pci_dev *pdev = mlxsw_pci->pdev; 142162306a36Sopenharmony_ci int err = 0; 142262306a36Sopenharmony_ci 142362306a36Sopenharmony_ci mbox->size = MLXSW_CMD_MBOX_SIZE; 142462306a36Sopenharmony_ci mbox->buf = dma_alloc_coherent(&pdev->dev, MLXSW_CMD_MBOX_SIZE, 142562306a36Sopenharmony_ci &mbox->mapaddr, GFP_KERNEL); 142662306a36Sopenharmony_ci if (!mbox->buf) { 142762306a36Sopenharmony_ci dev_err(&pdev->dev, "Failed allocating memory for mailbox\n"); 142862306a36Sopenharmony_ci err = -ENOMEM; 142962306a36Sopenharmony_ci } 143062306a36Sopenharmony_ci 143162306a36Sopenharmony_ci return err; 143262306a36Sopenharmony_ci} 143362306a36Sopenharmony_ci 143462306a36Sopenharmony_cistatic void mlxsw_pci_mbox_free(struct mlxsw_pci *mlxsw_pci, 143562306a36Sopenharmony_ci struct mlxsw_pci_mem_item *mbox) 143662306a36Sopenharmony_ci{ 143762306a36Sopenharmony_ci struct pci_dev *pdev = mlxsw_pci->pdev; 143862306a36Sopenharmony_ci 143962306a36Sopenharmony_ci dma_free_coherent(&pdev->dev, MLXSW_CMD_MBOX_SIZE, mbox->buf, 144062306a36Sopenharmony_ci mbox->mapaddr); 144162306a36Sopenharmony_ci} 144262306a36Sopenharmony_ci 144362306a36Sopenharmony_cistatic int mlxsw_pci_sys_ready_wait(struct mlxsw_pci *mlxsw_pci, 144462306a36Sopenharmony_ci const struct pci_device_id *id, 144562306a36Sopenharmony_ci u32 *p_sys_status) 144662306a36Sopenharmony_ci{ 144762306a36Sopenharmony_ci unsigned long end; 144862306a36Sopenharmony_ci u32 val; 144962306a36Sopenharmony_ci 145062306a36Sopenharmony_ci /* We must wait for the HW to become responsive. */ 145162306a36Sopenharmony_ci msleep(MLXSW_PCI_SW_RESET_WAIT_MSECS); 145262306a36Sopenharmony_ci 145362306a36Sopenharmony_ci end = jiffies + msecs_to_jiffies(MLXSW_PCI_SW_RESET_TIMEOUT_MSECS); 145462306a36Sopenharmony_ci do { 145562306a36Sopenharmony_ci val = mlxsw_pci_read32(mlxsw_pci, FW_READY); 145662306a36Sopenharmony_ci if ((val & MLXSW_PCI_FW_READY_MASK) == MLXSW_PCI_FW_READY_MAGIC) 145762306a36Sopenharmony_ci return 0; 145862306a36Sopenharmony_ci cond_resched(); 145962306a36Sopenharmony_ci } while (time_before(jiffies, end)); 146062306a36Sopenharmony_ci 146162306a36Sopenharmony_ci *p_sys_status = val & MLXSW_PCI_FW_READY_MASK; 146262306a36Sopenharmony_ci 146362306a36Sopenharmony_ci return -EBUSY; 146462306a36Sopenharmony_ci} 146562306a36Sopenharmony_ci 146662306a36Sopenharmony_cistatic int mlxsw_pci_sw_reset(struct mlxsw_pci *mlxsw_pci, 146762306a36Sopenharmony_ci const struct pci_device_id *id) 146862306a36Sopenharmony_ci{ 146962306a36Sopenharmony_ci struct pci_dev *pdev = mlxsw_pci->pdev; 147062306a36Sopenharmony_ci char mrsr_pl[MLXSW_REG_MRSR_LEN]; 147162306a36Sopenharmony_ci u32 sys_status; 147262306a36Sopenharmony_ci int err; 147362306a36Sopenharmony_ci 147462306a36Sopenharmony_ci err = mlxsw_pci_sys_ready_wait(mlxsw_pci, id, &sys_status); 147562306a36Sopenharmony_ci if (err) { 147662306a36Sopenharmony_ci dev_err(&pdev->dev, "Failed to reach system ready status before reset. Status is 0x%x\n", 147762306a36Sopenharmony_ci sys_status); 147862306a36Sopenharmony_ci return err; 147962306a36Sopenharmony_ci } 148062306a36Sopenharmony_ci 148162306a36Sopenharmony_ci mlxsw_reg_mrsr_pack(mrsr_pl); 148262306a36Sopenharmony_ci err = mlxsw_reg_write(mlxsw_pci->core, MLXSW_REG(mrsr), mrsr_pl); 148362306a36Sopenharmony_ci if (err) 148462306a36Sopenharmony_ci return err; 148562306a36Sopenharmony_ci 148662306a36Sopenharmony_ci err = mlxsw_pci_sys_ready_wait(mlxsw_pci, id, &sys_status); 148762306a36Sopenharmony_ci if (err) { 148862306a36Sopenharmony_ci dev_err(&pdev->dev, "Failed to reach system ready status after reset. Status is 0x%x\n", 148962306a36Sopenharmony_ci sys_status); 149062306a36Sopenharmony_ci return err; 149162306a36Sopenharmony_ci } 149262306a36Sopenharmony_ci 149362306a36Sopenharmony_ci return 0; 149462306a36Sopenharmony_ci} 149562306a36Sopenharmony_ci 149662306a36Sopenharmony_cistatic int mlxsw_pci_alloc_irq_vectors(struct mlxsw_pci *mlxsw_pci) 149762306a36Sopenharmony_ci{ 149862306a36Sopenharmony_ci int err; 149962306a36Sopenharmony_ci 150062306a36Sopenharmony_ci err = pci_alloc_irq_vectors(mlxsw_pci->pdev, 1, 1, PCI_IRQ_MSIX); 150162306a36Sopenharmony_ci if (err < 0) 150262306a36Sopenharmony_ci dev_err(&mlxsw_pci->pdev->dev, "MSI-X init failed\n"); 150362306a36Sopenharmony_ci return err; 150462306a36Sopenharmony_ci} 150562306a36Sopenharmony_ci 150662306a36Sopenharmony_cistatic void mlxsw_pci_free_irq_vectors(struct mlxsw_pci *mlxsw_pci) 150762306a36Sopenharmony_ci{ 150862306a36Sopenharmony_ci pci_free_irq_vectors(mlxsw_pci->pdev); 150962306a36Sopenharmony_ci} 151062306a36Sopenharmony_ci 151162306a36Sopenharmony_cistatic int mlxsw_pci_init(void *bus_priv, struct mlxsw_core *mlxsw_core, 151262306a36Sopenharmony_ci const struct mlxsw_config_profile *profile, 151362306a36Sopenharmony_ci struct mlxsw_res *res) 151462306a36Sopenharmony_ci{ 151562306a36Sopenharmony_ci struct mlxsw_pci *mlxsw_pci = bus_priv; 151662306a36Sopenharmony_ci struct pci_dev *pdev = mlxsw_pci->pdev; 151762306a36Sopenharmony_ci char *mbox; 151862306a36Sopenharmony_ci u16 num_pages; 151962306a36Sopenharmony_ci int err; 152062306a36Sopenharmony_ci 152162306a36Sopenharmony_ci mlxsw_pci->core = mlxsw_core; 152262306a36Sopenharmony_ci 152362306a36Sopenharmony_ci mbox = mlxsw_cmd_mbox_alloc(); 152462306a36Sopenharmony_ci if (!mbox) 152562306a36Sopenharmony_ci return -ENOMEM; 152662306a36Sopenharmony_ci 152762306a36Sopenharmony_ci err = mlxsw_pci_sw_reset(mlxsw_pci, mlxsw_pci->id); 152862306a36Sopenharmony_ci if (err) 152962306a36Sopenharmony_ci goto err_sw_reset; 153062306a36Sopenharmony_ci 153162306a36Sopenharmony_ci err = mlxsw_pci_alloc_irq_vectors(mlxsw_pci); 153262306a36Sopenharmony_ci if (err < 0) { 153362306a36Sopenharmony_ci dev_err(&pdev->dev, "MSI-X init failed\n"); 153462306a36Sopenharmony_ci goto err_alloc_irq; 153562306a36Sopenharmony_ci } 153662306a36Sopenharmony_ci 153762306a36Sopenharmony_ci err = mlxsw_cmd_query_fw(mlxsw_core, mbox); 153862306a36Sopenharmony_ci if (err) 153962306a36Sopenharmony_ci goto err_query_fw; 154062306a36Sopenharmony_ci 154162306a36Sopenharmony_ci mlxsw_pci->bus_info.fw_rev.major = 154262306a36Sopenharmony_ci mlxsw_cmd_mbox_query_fw_fw_rev_major_get(mbox); 154362306a36Sopenharmony_ci mlxsw_pci->bus_info.fw_rev.minor = 154462306a36Sopenharmony_ci mlxsw_cmd_mbox_query_fw_fw_rev_minor_get(mbox); 154562306a36Sopenharmony_ci mlxsw_pci->bus_info.fw_rev.subminor = 154662306a36Sopenharmony_ci mlxsw_cmd_mbox_query_fw_fw_rev_subminor_get(mbox); 154762306a36Sopenharmony_ci 154862306a36Sopenharmony_ci if (mlxsw_cmd_mbox_query_fw_cmd_interface_rev_get(mbox) != 1) { 154962306a36Sopenharmony_ci dev_err(&pdev->dev, "Unsupported cmd interface revision ID queried from hw\n"); 155062306a36Sopenharmony_ci err = -EINVAL; 155162306a36Sopenharmony_ci goto err_iface_rev; 155262306a36Sopenharmony_ci } 155362306a36Sopenharmony_ci if (mlxsw_cmd_mbox_query_fw_doorbell_page_bar_get(mbox) != 0) { 155462306a36Sopenharmony_ci dev_err(&pdev->dev, "Unsupported doorbell page bar queried from hw\n"); 155562306a36Sopenharmony_ci err = -EINVAL; 155662306a36Sopenharmony_ci goto err_doorbell_page_bar; 155762306a36Sopenharmony_ci } 155862306a36Sopenharmony_ci 155962306a36Sopenharmony_ci mlxsw_pci->doorbell_offset = 156062306a36Sopenharmony_ci mlxsw_cmd_mbox_query_fw_doorbell_page_offset_get(mbox); 156162306a36Sopenharmony_ci 156262306a36Sopenharmony_ci if (mlxsw_cmd_mbox_query_fw_fr_rn_clk_bar_get(mbox) != 0) { 156362306a36Sopenharmony_ci dev_err(&pdev->dev, "Unsupported free running clock BAR queried from hw\n"); 156462306a36Sopenharmony_ci err = -EINVAL; 156562306a36Sopenharmony_ci goto err_fr_rn_clk_bar; 156662306a36Sopenharmony_ci } 156762306a36Sopenharmony_ci 156862306a36Sopenharmony_ci mlxsw_pci->free_running_clock_offset = 156962306a36Sopenharmony_ci mlxsw_cmd_mbox_query_fw_free_running_clock_offset_get(mbox); 157062306a36Sopenharmony_ci 157162306a36Sopenharmony_ci if (mlxsw_cmd_mbox_query_fw_utc_sec_bar_get(mbox) != 0) { 157262306a36Sopenharmony_ci dev_err(&pdev->dev, "Unsupported UTC sec BAR queried from hw\n"); 157362306a36Sopenharmony_ci err = -EINVAL; 157462306a36Sopenharmony_ci goto err_utc_sec_bar; 157562306a36Sopenharmony_ci } 157662306a36Sopenharmony_ci 157762306a36Sopenharmony_ci mlxsw_pci->utc_sec_offset = 157862306a36Sopenharmony_ci mlxsw_cmd_mbox_query_fw_utc_sec_offset_get(mbox); 157962306a36Sopenharmony_ci 158062306a36Sopenharmony_ci if (mlxsw_cmd_mbox_query_fw_utc_nsec_bar_get(mbox) != 0) { 158162306a36Sopenharmony_ci dev_err(&pdev->dev, "Unsupported UTC nsec BAR queried from hw\n"); 158262306a36Sopenharmony_ci err = -EINVAL; 158362306a36Sopenharmony_ci goto err_utc_nsec_bar; 158462306a36Sopenharmony_ci } 158562306a36Sopenharmony_ci 158662306a36Sopenharmony_ci mlxsw_pci->utc_nsec_offset = 158762306a36Sopenharmony_ci mlxsw_cmd_mbox_query_fw_utc_nsec_offset_get(mbox); 158862306a36Sopenharmony_ci 158962306a36Sopenharmony_ci num_pages = mlxsw_cmd_mbox_query_fw_fw_pages_get(mbox); 159062306a36Sopenharmony_ci err = mlxsw_pci_fw_area_init(mlxsw_pci, mbox, num_pages); 159162306a36Sopenharmony_ci if (err) 159262306a36Sopenharmony_ci goto err_fw_area_init; 159362306a36Sopenharmony_ci 159462306a36Sopenharmony_ci err = mlxsw_pci_boardinfo(mlxsw_pci, mbox); 159562306a36Sopenharmony_ci if (err) 159662306a36Sopenharmony_ci goto err_boardinfo; 159762306a36Sopenharmony_ci 159862306a36Sopenharmony_ci err = mlxsw_core_resources_query(mlxsw_core, mbox, res); 159962306a36Sopenharmony_ci if (err) 160062306a36Sopenharmony_ci goto err_query_resources; 160162306a36Sopenharmony_ci 160262306a36Sopenharmony_ci if (MLXSW_CORE_RES_VALID(mlxsw_core, CQE_V2) && 160362306a36Sopenharmony_ci MLXSW_CORE_RES_GET(mlxsw_core, CQE_V2)) 160462306a36Sopenharmony_ci mlxsw_pci->max_cqe_ver = MLXSW_PCI_CQE_V2; 160562306a36Sopenharmony_ci else if (MLXSW_CORE_RES_VALID(mlxsw_core, CQE_V1) && 160662306a36Sopenharmony_ci MLXSW_CORE_RES_GET(mlxsw_core, CQE_V1)) 160762306a36Sopenharmony_ci mlxsw_pci->max_cqe_ver = MLXSW_PCI_CQE_V1; 160862306a36Sopenharmony_ci else if ((MLXSW_CORE_RES_VALID(mlxsw_core, CQE_V0) && 160962306a36Sopenharmony_ci MLXSW_CORE_RES_GET(mlxsw_core, CQE_V0)) || 161062306a36Sopenharmony_ci !MLXSW_CORE_RES_VALID(mlxsw_core, CQE_V0)) { 161162306a36Sopenharmony_ci mlxsw_pci->max_cqe_ver = MLXSW_PCI_CQE_V0; 161262306a36Sopenharmony_ci } else { 161362306a36Sopenharmony_ci dev_err(&pdev->dev, "Invalid supported CQE version combination reported\n"); 161462306a36Sopenharmony_ci goto err_cqe_v_check; 161562306a36Sopenharmony_ci } 161662306a36Sopenharmony_ci 161762306a36Sopenharmony_ci err = mlxsw_pci_config_profile(mlxsw_pci, mbox, profile, res); 161862306a36Sopenharmony_ci if (err) 161962306a36Sopenharmony_ci goto err_config_profile; 162062306a36Sopenharmony_ci 162162306a36Sopenharmony_ci /* Some resources depend on unified bridge model, which is configured 162262306a36Sopenharmony_ci * as part of config_profile. Query the resources again to get correct 162362306a36Sopenharmony_ci * values. 162462306a36Sopenharmony_ci */ 162562306a36Sopenharmony_ci err = mlxsw_core_resources_query(mlxsw_core, mbox, res); 162662306a36Sopenharmony_ci if (err) 162762306a36Sopenharmony_ci goto err_requery_resources; 162862306a36Sopenharmony_ci 162962306a36Sopenharmony_ci err = mlxsw_pci_aqs_init(mlxsw_pci, mbox); 163062306a36Sopenharmony_ci if (err) 163162306a36Sopenharmony_ci goto err_aqs_init; 163262306a36Sopenharmony_ci 163362306a36Sopenharmony_ci err = request_irq(pci_irq_vector(pdev, 0), 163462306a36Sopenharmony_ci mlxsw_pci_eq_irq_handler, 0, 163562306a36Sopenharmony_ci mlxsw_pci->bus_info.device_kind, mlxsw_pci); 163662306a36Sopenharmony_ci if (err) { 163762306a36Sopenharmony_ci dev_err(&pdev->dev, "IRQ request failed\n"); 163862306a36Sopenharmony_ci goto err_request_eq_irq; 163962306a36Sopenharmony_ci } 164062306a36Sopenharmony_ci 164162306a36Sopenharmony_ci goto mbox_put; 164262306a36Sopenharmony_ci 164362306a36Sopenharmony_cierr_request_eq_irq: 164462306a36Sopenharmony_ci mlxsw_pci_aqs_fini(mlxsw_pci); 164562306a36Sopenharmony_cierr_aqs_init: 164662306a36Sopenharmony_cierr_requery_resources: 164762306a36Sopenharmony_cierr_config_profile: 164862306a36Sopenharmony_cierr_cqe_v_check: 164962306a36Sopenharmony_cierr_query_resources: 165062306a36Sopenharmony_cierr_boardinfo: 165162306a36Sopenharmony_ci mlxsw_pci_fw_area_fini(mlxsw_pci); 165262306a36Sopenharmony_cierr_fw_area_init: 165362306a36Sopenharmony_cierr_utc_nsec_bar: 165462306a36Sopenharmony_cierr_utc_sec_bar: 165562306a36Sopenharmony_cierr_fr_rn_clk_bar: 165662306a36Sopenharmony_cierr_doorbell_page_bar: 165762306a36Sopenharmony_cierr_iface_rev: 165862306a36Sopenharmony_cierr_query_fw: 165962306a36Sopenharmony_ci mlxsw_pci_free_irq_vectors(mlxsw_pci); 166062306a36Sopenharmony_cierr_alloc_irq: 166162306a36Sopenharmony_cierr_sw_reset: 166262306a36Sopenharmony_cimbox_put: 166362306a36Sopenharmony_ci mlxsw_cmd_mbox_free(mbox); 166462306a36Sopenharmony_ci return err; 166562306a36Sopenharmony_ci} 166662306a36Sopenharmony_ci 166762306a36Sopenharmony_cistatic void mlxsw_pci_fini(void *bus_priv) 166862306a36Sopenharmony_ci{ 166962306a36Sopenharmony_ci struct mlxsw_pci *mlxsw_pci = bus_priv; 167062306a36Sopenharmony_ci 167162306a36Sopenharmony_ci free_irq(pci_irq_vector(mlxsw_pci->pdev, 0), mlxsw_pci); 167262306a36Sopenharmony_ci mlxsw_pci_aqs_fini(mlxsw_pci); 167362306a36Sopenharmony_ci mlxsw_pci_fw_area_fini(mlxsw_pci); 167462306a36Sopenharmony_ci mlxsw_pci_free_irq_vectors(mlxsw_pci); 167562306a36Sopenharmony_ci} 167662306a36Sopenharmony_ci 167762306a36Sopenharmony_cistatic struct mlxsw_pci_queue * 167862306a36Sopenharmony_cimlxsw_pci_sdq_pick(struct mlxsw_pci *mlxsw_pci, 167962306a36Sopenharmony_ci const struct mlxsw_tx_info *tx_info) 168062306a36Sopenharmony_ci{ 168162306a36Sopenharmony_ci u8 ctl_sdq_count = mlxsw_pci_sdq_count(mlxsw_pci) - 1; 168262306a36Sopenharmony_ci u8 sdqn; 168362306a36Sopenharmony_ci 168462306a36Sopenharmony_ci if (tx_info->is_emad) { 168562306a36Sopenharmony_ci sdqn = MLXSW_PCI_SDQ_EMAD_INDEX; 168662306a36Sopenharmony_ci } else { 168762306a36Sopenharmony_ci BUILD_BUG_ON(MLXSW_PCI_SDQ_EMAD_INDEX != 0); 168862306a36Sopenharmony_ci sdqn = 1 + (tx_info->local_port % ctl_sdq_count); 168962306a36Sopenharmony_ci } 169062306a36Sopenharmony_ci 169162306a36Sopenharmony_ci return mlxsw_pci_sdq_get(mlxsw_pci, sdqn); 169262306a36Sopenharmony_ci} 169362306a36Sopenharmony_ci 169462306a36Sopenharmony_cistatic bool mlxsw_pci_skb_transmit_busy(void *bus_priv, 169562306a36Sopenharmony_ci const struct mlxsw_tx_info *tx_info) 169662306a36Sopenharmony_ci{ 169762306a36Sopenharmony_ci struct mlxsw_pci *mlxsw_pci = bus_priv; 169862306a36Sopenharmony_ci struct mlxsw_pci_queue *q = mlxsw_pci_sdq_pick(mlxsw_pci, tx_info); 169962306a36Sopenharmony_ci 170062306a36Sopenharmony_ci return !mlxsw_pci_queue_elem_info_producer_get(q); 170162306a36Sopenharmony_ci} 170262306a36Sopenharmony_ci 170362306a36Sopenharmony_cistatic int mlxsw_pci_skb_transmit(void *bus_priv, struct sk_buff *skb, 170462306a36Sopenharmony_ci const struct mlxsw_tx_info *tx_info) 170562306a36Sopenharmony_ci{ 170662306a36Sopenharmony_ci struct mlxsw_pci *mlxsw_pci = bus_priv; 170762306a36Sopenharmony_ci struct mlxsw_pci_queue *q; 170862306a36Sopenharmony_ci struct mlxsw_pci_queue_elem_info *elem_info; 170962306a36Sopenharmony_ci char *wqe; 171062306a36Sopenharmony_ci int i; 171162306a36Sopenharmony_ci int err; 171262306a36Sopenharmony_ci 171362306a36Sopenharmony_ci if (skb_shinfo(skb)->nr_frags > MLXSW_PCI_WQE_SG_ENTRIES - 1) { 171462306a36Sopenharmony_ci err = skb_linearize(skb); 171562306a36Sopenharmony_ci if (err) 171662306a36Sopenharmony_ci return err; 171762306a36Sopenharmony_ci } 171862306a36Sopenharmony_ci 171962306a36Sopenharmony_ci q = mlxsw_pci_sdq_pick(mlxsw_pci, tx_info); 172062306a36Sopenharmony_ci spin_lock_bh(&q->lock); 172162306a36Sopenharmony_ci elem_info = mlxsw_pci_queue_elem_info_producer_get(q); 172262306a36Sopenharmony_ci if (!elem_info) { 172362306a36Sopenharmony_ci /* queue is full */ 172462306a36Sopenharmony_ci err = -EAGAIN; 172562306a36Sopenharmony_ci goto unlock; 172662306a36Sopenharmony_ci } 172762306a36Sopenharmony_ci mlxsw_skb_cb(skb)->tx_info = *tx_info; 172862306a36Sopenharmony_ci elem_info->u.sdq.skb = skb; 172962306a36Sopenharmony_ci 173062306a36Sopenharmony_ci wqe = elem_info->elem; 173162306a36Sopenharmony_ci mlxsw_pci_wqe_c_set(wqe, 1); /* always report completion */ 173262306a36Sopenharmony_ci mlxsw_pci_wqe_lp_set(wqe, 0); 173362306a36Sopenharmony_ci mlxsw_pci_wqe_type_set(wqe, MLXSW_PCI_WQE_TYPE_ETHERNET); 173462306a36Sopenharmony_ci 173562306a36Sopenharmony_ci err = mlxsw_pci_wqe_frag_map(mlxsw_pci, wqe, 0, skb->data, 173662306a36Sopenharmony_ci skb_headlen(skb), DMA_TO_DEVICE); 173762306a36Sopenharmony_ci if (err) 173862306a36Sopenharmony_ci goto unlock; 173962306a36Sopenharmony_ci 174062306a36Sopenharmony_ci for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { 174162306a36Sopenharmony_ci const skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; 174262306a36Sopenharmony_ci 174362306a36Sopenharmony_ci err = mlxsw_pci_wqe_frag_map(mlxsw_pci, wqe, i + 1, 174462306a36Sopenharmony_ci skb_frag_address(frag), 174562306a36Sopenharmony_ci skb_frag_size(frag), 174662306a36Sopenharmony_ci DMA_TO_DEVICE); 174762306a36Sopenharmony_ci if (err) 174862306a36Sopenharmony_ci goto unmap_frags; 174962306a36Sopenharmony_ci } 175062306a36Sopenharmony_ci 175162306a36Sopenharmony_ci if (unlikely(skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP)) 175262306a36Sopenharmony_ci skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS; 175362306a36Sopenharmony_ci 175462306a36Sopenharmony_ci /* Set unused sq entries byte count to zero. */ 175562306a36Sopenharmony_ci for (i++; i < MLXSW_PCI_WQE_SG_ENTRIES; i++) 175662306a36Sopenharmony_ci mlxsw_pci_wqe_byte_count_set(wqe, i, 0); 175762306a36Sopenharmony_ci 175862306a36Sopenharmony_ci /* Everything is set up, ring producer doorbell to get HW going */ 175962306a36Sopenharmony_ci q->producer_counter++; 176062306a36Sopenharmony_ci mlxsw_pci_queue_doorbell_producer_ring(mlxsw_pci, q); 176162306a36Sopenharmony_ci 176262306a36Sopenharmony_ci goto unlock; 176362306a36Sopenharmony_ci 176462306a36Sopenharmony_ciunmap_frags: 176562306a36Sopenharmony_ci for (; i >= 0; i--) 176662306a36Sopenharmony_ci mlxsw_pci_wqe_frag_unmap(mlxsw_pci, wqe, i, DMA_TO_DEVICE); 176762306a36Sopenharmony_ciunlock: 176862306a36Sopenharmony_ci spin_unlock_bh(&q->lock); 176962306a36Sopenharmony_ci return err; 177062306a36Sopenharmony_ci} 177162306a36Sopenharmony_ci 177262306a36Sopenharmony_cistatic int mlxsw_pci_cmd_exec(void *bus_priv, u16 opcode, u8 opcode_mod, 177362306a36Sopenharmony_ci u32 in_mod, bool out_mbox_direct, 177462306a36Sopenharmony_ci char *in_mbox, size_t in_mbox_size, 177562306a36Sopenharmony_ci char *out_mbox, size_t out_mbox_size, 177662306a36Sopenharmony_ci u8 *p_status) 177762306a36Sopenharmony_ci{ 177862306a36Sopenharmony_ci struct mlxsw_pci *mlxsw_pci = bus_priv; 177962306a36Sopenharmony_ci dma_addr_t in_mapaddr = 0, out_mapaddr = 0; 178062306a36Sopenharmony_ci bool evreq = mlxsw_pci->cmd.nopoll; 178162306a36Sopenharmony_ci unsigned long timeout = msecs_to_jiffies(MLXSW_PCI_CIR_TIMEOUT_MSECS); 178262306a36Sopenharmony_ci bool *p_wait_done = &mlxsw_pci->cmd.wait_done; 178362306a36Sopenharmony_ci int err; 178462306a36Sopenharmony_ci 178562306a36Sopenharmony_ci *p_status = MLXSW_CMD_STATUS_OK; 178662306a36Sopenharmony_ci 178762306a36Sopenharmony_ci err = mutex_lock_interruptible(&mlxsw_pci->cmd.lock); 178862306a36Sopenharmony_ci if (err) 178962306a36Sopenharmony_ci return err; 179062306a36Sopenharmony_ci 179162306a36Sopenharmony_ci if (in_mbox) { 179262306a36Sopenharmony_ci memcpy(mlxsw_pci->cmd.in_mbox.buf, in_mbox, in_mbox_size); 179362306a36Sopenharmony_ci in_mapaddr = mlxsw_pci->cmd.in_mbox.mapaddr; 179462306a36Sopenharmony_ci } 179562306a36Sopenharmony_ci mlxsw_pci_write32(mlxsw_pci, CIR_IN_PARAM_HI, upper_32_bits(in_mapaddr)); 179662306a36Sopenharmony_ci mlxsw_pci_write32(mlxsw_pci, CIR_IN_PARAM_LO, lower_32_bits(in_mapaddr)); 179762306a36Sopenharmony_ci 179862306a36Sopenharmony_ci if (out_mbox) 179962306a36Sopenharmony_ci out_mapaddr = mlxsw_pci->cmd.out_mbox.mapaddr; 180062306a36Sopenharmony_ci mlxsw_pci_write32(mlxsw_pci, CIR_OUT_PARAM_HI, upper_32_bits(out_mapaddr)); 180162306a36Sopenharmony_ci mlxsw_pci_write32(mlxsw_pci, CIR_OUT_PARAM_LO, lower_32_bits(out_mapaddr)); 180262306a36Sopenharmony_ci 180362306a36Sopenharmony_ci mlxsw_pci_write32(mlxsw_pci, CIR_IN_MODIFIER, in_mod); 180462306a36Sopenharmony_ci mlxsw_pci_write32(mlxsw_pci, CIR_TOKEN, 0); 180562306a36Sopenharmony_ci 180662306a36Sopenharmony_ci *p_wait_done = false; 180762306a36Sopenharmony_ci 180862306a36Sopenharmony_ci wmb(); /* all needs to be written before we write control register */ 180962306a36Sopenharmony_ci mlxsw_pci_write32(mlxsw_pci, CIR_CTRL, 181062306a36Sopenharmony_ci MLXSW_PCI_CIR_CTRL_GO_BIT | 181162306a36Sopenharmony_ci (evreq ? MLXSW_PCI_CIR_CTRL_EVREQ_BIT : 0) | 181262306a36Sopenharmony_ci (opcode_mod << MLXSW_PCI_CIR_CTRL_OPCODE_MOD_SHIFT) | 181362306a36Sopenharmony_ci opcode); 181462306a36Sopenharmony_ci 181562306a36Sopenharmony_ci if (!evreq) { 181662306a36Sopenharmony_ci unsigned long end; 181762306a36Sopenharmony_ci 181862306a36Sopenharmony_ci end = jiffies + timeout; 181962306a36Sopenharmony_ci do { 182062306a36Sopenharmony_ci u32 ctrl = mlxsw_pci_read32(mlxsw_pci, CIR_CTRL); 182162306a36Sopenharmony_ci 182262306a36Sopenharmony_ci if (!(ctrl & MLXSW_PCI_CIR_CTRL_GO_BIT)) { 182362306a36Sopenharmony_ci *p_wait_done = true; 182462306a36Sopenharmony_ci *p_status = ctrl >> MLXSW_PCI_CIR_CTRL_STATUS_SHIFT; 182562306a36Sopenharmony_ci break; 182662306a36Sopenharmony_ci } 182762306a36Sopenharmony_ci cond_resched(); 182862306a36Sopenharmony_ci } while (time_before(jiffies, end)); 182962306a36Sopenharmony_ci } else { 183062306a36Sopenharmony_ci wait_event_timeout(mlxsw_pci->cmd.wait, *p_wait_done, timeout); 183162306a36Sopenharmony_ci *p_status = mlxsw_pci->cmd.comp.status; 183262306a36Sopenharmony_ci } 183362306a36Sopenharmony_ci 183462306a36Sopenharmony_ci err = 0; 183562306a36Sopenharmony_ci if (*p_wait_done) { 183662306a36Sopenharmony_ci if (*p_status) 183762306a36Sopenharmony_ci err = -EIO; 183862306a36Sopenharmony_ci } else { 183962306a36Sopenharmony_ci err = -ETIMEDOUT; 184062306a36Sopenharmony_ci } 184162306a36Sopenharmony_ci 184262306a36Sopenharmony_ci if (!err && out_mbox && out_mbox_direct) { 184362306a36Sopenharmony_ci /* Some commands don't use output param as address to mailbox 184462306a36Sopenharmony_ci * but they store output directly into registers. In that case, 184562306a36Sopenharmony_ci * copy registers into mbox buffer. 184662306a36Sopenharmony_ci */ 184762306a36Sopenharmony_ci __be32 tmp; 184862306a36Sopenharmony_ci 184962306a36Sopenharmony_ci if (!evreq) { 185062306a36Sopenharmony_ci tmp = cpu_to_be32(mlxsw_pci_read32(mlxsw_pci, 185162306a36Sopenharmony_ci CIR_OUT_PARAM_HI)); 185262306a36Sopenharmony_ci memcpy(out_mbox, &tmp, sizeof(tmp)); 185362306a36Sopenharmony_ci tmp = cpu_to_be32(mlxsw_pci_read32(mlxsw_pci, 185462306a36Sopenharmony_ci CIR_OUT_PARAM_LO)); 185562306a36Sopenharmony_ci memcpy(out_mbox + sizeof(tmp), &tmp, sizeof(tmp)); 185662306a36Sopenharmony_ci } 185762306a36Sopenharmony_ci } else if (!err && out_mbox) { 185862306a36Sopenharmony_ci memcpy(out_mbox, mlxsw_pci->cmd.out_mbox.buf, out_mbox_size); 185962306a36Sopenharmony_ci } 186062306a36Sopenharmony_ci 186162306a36Sopenharmony_ci mutex_unlock(&mlxsw_pci->cmd.lock); 186262306a36Sopenharmony_ci 186362306a36Sopenharmony_ci return err; 186462306a36Sopenharmony_ci} 186562306a36Sopenharmony_ci 186662306a36Sopenharmony_cistatic u32 mlxsw_pci_read_frc_h(void *bus_priv) 186762306a36Sopenharmony_ci{ 186862306a36Sopenharmony_ci struct mlxsw_pci *mlxsw_pci = bus_priv; 186962306a36Sopenharmony_ci u64 frc_offset_h; 187062306a36Sopenharmony_ci 187162306a36Sopenharmony_ci frc_offset_h = mlxsw_pci->free_running_clock_offset; 187262306a36Sopenharmony_ci return mlxsw_pci_read32_off(mlxsw_pci, frc_offset_h); 187362306a36Sopenharmony_ci} 187462306a36Sopenharmony_ci 187562306a36Sopenharmony_cistatic u32 mlxsw_pci_read_frc_l(void *bus_priv) 187662306a36Sopenharmony_ci{ 187762306a36Sopenharmony_ci struct mlxsw_pci *mlxsw_pci = bus_priv; 187862306a36Sopenharmony_ci u64 frc_offset_l; 187962306a36Sopenharmony_ci 188062306a36Sopenharmony_ci frc_offset_l = mlxsw_pci->free_running_clock_offset + 4; 188162306a36Sopenharmony_ci return mlxsw_pci_read32_off(mlxsw_pci, frc_offset_l); 188262306a36Sopenharmony_ci} 188362306a36Sopenharmony_ci 188462306a36Sopenharmony_cistatic u32 mlxsw_pci_read_utc_sec(void *bus_priv) 188562306a36Sopenharmony_ci{ 188662306a36Sopenharmony_ci struct mlxsw_pci *mlxsw_pci = bus_priv; 188762306a36Sopenharmony_ci 188862306a36Sopenharmony_ci return mlxsw_pci_read32_off(mlxsw_pci, mlxsw_pci->utc_sec_offset); 188962306a36Sopenharmony_ci} 189062306a36Sopenharmony_ci 189162306a36Sopenharmony_cistatic u32 mlxsw_pci_read_utc_nsec(void *bus_priv) 189262306a36Sopenharmony_ci{ 189362306a36Sopenharmony_ci struct mlxsw_pci *mlxsw_pci = bus_priv; 189462306a36Sopenharmony_ci 189562306a36Sopenharmony_ci return mlxsw_pci_read32_off(mlxsw_pci, mlxsw_pci->utc_nsec_offset); 189662306a36Sopenharmony_ci} 189762306a36Sopenharmony_ci 189862306a36Sopenharmony_cistatic const struct mlxsw_bus mlxsw_pci_bus = { 189962306a36Sopenharmony_ci .kind = "pci", 190062306a36Sopenharmony_ci .init = mlxsw_pci_init, 190162306a36Sopenharmony_ci .fini = mlxsw_pci_fini, 190262306a36Sopenharmony_ci .skb_transmit_busy = mlxsw_pci_skb_transmit_busy, 190362306a36Sopenharmony_ci .skb_transmit = mlxsw_pci_skb_transmit, 190462306a36Sopenharmony_ci .cmd_exec = mlxsw_pci_cmd_exec, 190562306a36Sopenharmony_ci .read_frc_h = mlxsw_pci_read_frc_h, 190662306a36Sopenharmony_ci .read_frc_l = mlxsw_pci_read_frc_l, 190762306a36Sopenharmony_ci .read_utc_sec = mlxsw_pci_read_utc_sec, 190862306a36Sopenharmony_ci .read_utc_nsec = mlxsw_pci_read_utc_nsec, 190962306a36Sopenharmony_ci .features = MLXSW_BUS_F_TXRX | MLXSW_BUS_F_RESET, 191062306a36Sopenharmony_ci}; 191162306a36Sopenharmony_ci 191262306a36Sopenharmony_cistatic int mlxsw_pci_cmd_init(struct mlxsw_pci *mlxsw_pci) 191362306a36Sopenharmony_ci{ 191462306a36Sopenharmony_ci int err; 191562306a36Sopenharmony_ci 191662306a36Sopenharmony_ci mutex_init(&mlxsw_pci->cmd.lock); 191762306a36Sopenharmony_ci init_waitqueue_head(&mlxsw_pci->cmd.wait); 191862306a36Sopenharmony_ci 191962306a36Sopenharmony_ci err = mlxsw_pci_mbox_alloc(mlxsw_pci, &mlxsw_pci->cmd.in_mbox); 192062306a36Sopenharmony_ci if (err) 192162306a36Sopenharmony_ci goto err_in_mbox_alloc; 192262306a36Sopenharmony_ci 192362306a36Sopenharmony_ci err = mlxsw_pci_mbox_alloc(mlxsw_pci, &mlxsw_pci->cmd.out_mbox); 192462306a36Sopenharmony_ci if (err) 192562306a36Sopenharmony_ci goto err_out_mbox_alloc; 192662306a36Sopenharmony_ci 192762306a36Sopenharmony_ci return 0; 192862306a36Sopenharmony_ci 192962306a36Sopenharmony_cierr_out_mbox_alloc: 193062306a36Sopenharmony_ci mlxsw_pci_mbox_free(mlxsw_pci, &mlxsw_pci->cmd.in_mbox); 193162306a36Sopenharmony_cierr_in_mbox_alloc: 193262306a36Sopenharmony_ci mutex_destroy(&mlxsw_pci->cmd.lock); 193362306a36Sopenharmony_ci return err; 193462306a36Sopenharmony_ci} 193562306a36Sopenharmony_ci 193662306a36Sopenharmony_cistatic void mlxsw_pci_cmd_fini(struct mlxsw_pci *mlxsw_pci) 193762306a36Sopenharmony_ci{ 193862306a36Sopenharmony_ci mlxsw_pci_mbox_free(mlxsw_pci, &mlxsw_pci->cmd.out_mbox); 193962306a36Sopenharmony_ci mlxsw_pci_mbox_free(mlxsw_pci, &mlxsw_pci->cmd.in_mbox); 194062306a36Sopenharmony_ci mutex_destroy(&mlxsw_pci->cmd.lock); 194162306a36Sopenharmony_ci} 194262306a36Sopenharmony_ci 194362306a36Sopenharmony_cistatic int mlxsw_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) 194462306a36Sopenharmony_ci{ 194562306a36Sopenharmony_ci const char *driver_name = dev_driver_string(&pdev->dev); 194662306a36Sopenharmony_ci struct mlxsw_pci *mlxsw_pci; 194762306a36Sopenharmony_ci int err; 194862306a36Sopenharmony_ci 194962306a36Sopenharmony_ci mlxsw_pci = kzalloc(sizeof(*mlxsw_pci), GFP_KERNEL); 195062306a36Sopenharmony_ci if (!mlxsw_pci) 195162306a36Sopenharmony_ci return -ENOMEM; 195262306a36Sopenharmony_ci 195362306a36Sopenharmony_ci err = pci_enable_device(pdev); 195462306a36Sopenharmony_ci if (err) { 195562306a36Sopenharmony_ci dev_err(&pdev->dev, "pci_enable_device failed\n"); 195662306a36Sopenharmony_ci goto err_pci_enable_device; 195762306a36Sopenharmony_ci } 195862306a36Sopenharmony_ci 195962306a36Sopenharmony_ci err = pci_request_regions(pdev, driver_name); 196062306a36Sopenharmony_ci if (err) { 196162306a36Sopenharmony_ci dev_err(&pdev->dev, "pci_request_regions failed\n"); 196262306a36Sopenharmony_ci goto err_pci_request_regions; 196362306a36Sopenharmony_ci } 196462306a36Sopenharmony_ci 196562306a36Sopenharmony_ci err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64)); 196662306a36Sopenharmony_ci if (err) { 196762306a36Sopenharmony_ci err = dma_set_mask(&pdev->dev, DMA_BIT_MASK(32)); 196862306a36Sopenharmony_ci if (err) { 196962306a36Sopenharmony_ci dev_err(&pdev->dev, "dma_set_mask failed\n"); 197062306a36Sopenharmony_ci goto err_pci_set_dma_mask; 197162306a36Sopenharmony_ci } 197262306a36Sopenharmony_ci } 197362306a36Sopenharmony_ci 197462306a36Sopenharmony_ci if (pci_resource_len(pdev, 0) < MLXSW_PCI_BAR0_SIZE) { 197562306a36Sopenharmony_ci dev_err(&pdev->dev, "invalid PCI region size\n"); 197662306a36Sopenharmony_ci err = -EINVAL; 197762306a36Sopenharmony_ci goto err_pci_resource_len_check; 197862306a36Sopenharmony_ci } 197962306a36Sopenharmony_ci 198062306a36Sopenharmony_ci mlxsw_pci->hw_addr = ioremap(pci_resource_start(pdev, 0), 198162306a36Sopenharmony_ci pci_resource_len(pdev, 0)); 198262306a36Sopenharmony_ci if (!mlxsw_pci->hw_addr) { 198362306a36Sopenharmony_ci dev_err(&pdev->dev, "ioremap failed\n"); 198462306a36Sopenharmony_ci err = -EIO; 198562306a36Sopenharmony_ci goto err_ioremap; 198662306a36Sopenharmony_ci } 198762306a36Sopenharmony_ci pci_set_master(pdev); 198862306a36Sopenharmony_ci 198962306a36Sopenharmony_ci mlxsw_pci->pdev = pdev; 199062306a36Sopenharmony_ci pci_set_drvdata(pdev, mlxsw_pci); 199162306a36Sopenharmony_ci 199262306a36Sopenharmony_ci err = mlxsw_pci_cmd_init(mlxsw_pci); 199362306a36Sopenharmony_ci if (err) 199462306a36Sopenharmony_ci goto err_pci_cmd_init; 199562306a36Sopenharmony_ci 199662306a36Sopenharmony_ci mlxsw_pci->bus_info.device_kind = driver_name; 199762306a36Sopenharmony_ci mlxsw_pci->bus_info.device_name = pci_name(mlxsw_pci->pdev); 199862306a36Sopenharmony_ci mlxsw_pci->bus_info.dev = &pdev->dev; 199962306a36Sopenharmony_ci mlxsw_pci->bus_info.read_clock_capable = true; 200062306a36Sopenharmony_ci mlxsw_pci->id = id; 200162306a36Sopenharmony_ci 200262306a36Sopenharmony_ci err = mlxsw_core_bus_device_register(&mlxsw_pci->bus_info, 200362306a36Sopenharmony_ci &mlxsw_pci_bus, mlxsw_pci, false, 200462306a36Sopenharmony_ci NULL, NULL); 200562306a36Sopenharmony_ci if (err) { 200662306a36Sopenharmony_ci dev_err(&pdev->dev, "cannot register bus device\n"); 200762306a36Sopenharmony_ci goto err_bus_device_register; 200862306a36Sopenharmony_ci } 200962306a36Sopenharmony_ci 201062306a36Sopenharmony_ci return 0; 201162306a36Sopenharmony_ci 201262306a36Sopenharmony_cierr_bus_device_register: 201362306a36Sopenharmony_ci mlxsw_pci_cmd_fini(mlxsw_pci); 201462306a36Sopenharmony_cierr_pci_cmd_init: 201562306a36Sopenharmony_ci iounmap(mlxsw_pci->hw_addr); 201662306a36Sopenharmony_cierr_ioremap: 201762306a36Sopenharmony_cierr_pci_resource_len_check: 201862306a36Sopenharmony_cierr_pci_set_dma_mask: 201962306a36Sopenharmony_ci pci_release_regions(pdev); 202062306a36Sopenharmony_cierr_pci_request_regions: 202162306a36Sopenharmony_ci pci_disable_device(pdev); 202262306a36Sopenharmony_cierr_pci_enable_device: 202362306a36Sopenharmony_ci kfree(mlxsw_pci); 202462306a36Sopenharmony_ci return err; 202562306a36Sopenharmony_ci} 202662306a36Sopenharmony_ci 202762306a36Sopenharmony_cistatic void mlxsw_pci_remove(struct pci_dev *pdev) 202862306a36Sopenharmony_ci{ 202962306a36Sopenharmony_ci struct mlxsw_pci *mlxsw_pci = pci_get_drvdata(pdev); 203062306a36Sopenharmony_ci 203162306a36Sopenharmony_ci mlxsw_core_bus_device_unregister(mlxsw_pci->core, false); 203262306a36Sopenharmony_ci mlxsw_pci_cmd_fini(mlxsw_pci); 203362306a36Sopenharmony_ci iounmap(mlxsw_pci->hw_addr); 203462306a36Sopenharmony_ci pci_release_regions(mlxsw_pci->pdev); 203562306a36Sopenharmony_ci pci_disable_device(mlxsw_pci->pdev); 203662306a36Sopenharmony_ci kfree(mlxsw_pci); 203762306a36Sopenharmony_ci} 203862306a36Sopenharmony_ci 203962306a36Sopenharmony_ciint mlxsw_pci_driver_register(struct pci_driver *pci_driver) 204062306a36Sopenharmony_ci{ 204162306a36Sopenharmony_ci pci_driver->probe = mlxsw_pci_probe; 204262306a36Sopenharmony_ci pci_driver->remove = mlxsw_pci_remove; 204362306a36Sopenharmony_ci pci_driver->shutdown = mlxsw_pci_remove; 204462306a36Sopenharmony_ci return pci_register_driver(pci_driver); 204562306a36Sopenharmony_ci} 204662306a36Sopenharmony_ciEXPORT_SYMBOL(mlxsw_pci_driver_register); 204762306a36Sopenharmony_ci 204862306a36Sopenharmony_civoid mlxsw_pci_driver_unregister(struct pci_driver *pci_driver) 204962306a36Sopenharmony_ci{ 205062306a36Sopenharmony_ci pci_unregister_driver(pci_driver); 205162306a36Sopenharmony_ci} 205262306a36Sopenharmony_ciEXPORT_SYMBOL(mlxsw_pci_driver_unregister); 205362306a36Sopenharmony_ci 205462306a36Sopenharmony_cistatic int __init mlxsw_pci_module_init(void) 205562306a36Sopenharmony_ci{ 205662306a36Sopenharmony_ci return 0; 205762306a36Sopenharmony_ci} 205862306a36Sopenharmony_ci 205962306a36Sopenharmony_cistatic void __exit mlxsw_pci_module_exit(void) 206062306a36Sopenharmony_ci{ 206162306a36Sopenharmony_ci} 206262306a36Sopenharmony_ci 206362306a36Sopenharmony_cimodule_init(mlxsw_pci_module_init); 206462306a36Sopenharmony_cimodule_exit(mlxsw_pci_module_exit); 206562306a36Sopenharmony_ci 206662306a36Sopenharmony_ciMODULE_LICENSE("Dual BSD/GPL"); 206762306a36Sopenharmony_ciMODULE_AUTHOR("Jiri Pirko <jiri@mellanox.com>"); 206862306a36Sopenharmony_ciMODULE_DESCRIPTION("Mellanox switch PCI interface driver"); 2069