#define MLXSW_PCI_QUEUE_TYPE_COUNT 4
+enum mlxsw_pci_cq_type {
+ MLXSW_PCI_CQ_SDQ,
+ MLXSW_PCI_CQ_RDQ,
+};
+
static const u16 mlxsw_pci_doorbell_type_offset[] = {
MLXSW_PCI_DOORBELL_SDQ_OFFSET, /* for type MLXSW_PCI_QUEUE_TYPE_SDQ */
MLXSW_PCI_DOORBELL_RDQ_OFFSET, /* for type MLXSW_PCI_QUEUE_TYPE_RDQ */
return elem;
}
-static void mlxsw_pci_cq_tasklet(struct tasklet_struct *t)
+static void mlxsw_pci_cq_rx_tasklet(struct tasklet_struct *t)
{
struct mlxsw_pci_queue *q = from_tasklet(q, t, tasklet);
struct mlxsw_pci *mlxsw_pci = q->pci;
u8 sendq = mlxsw_pci_cqe_sr_get(q->cq.v, cqe);
u8 dqn = mlxsw_pci_cqe_dqn_get(q->cq.v, cqe);
char ncqe[MLXSW_PCI_CQE_SIZE_MAX];
+ struct mlxsw_pci_queue *rdq;
+
+ if (unlikely(sendq)) {
+ WARN_ON_ONCE(1);
+ continue;
+ }
memcpy(ncqe, cqe, q->elem_size);
mlxsw_pci_queue_doorbell_consumer_ring(mlxsw_pci, q);
- if (sendq) {
- struct mlxsw_pci_queue *sdq;
+ rdq = mlxsw_pci_rdq_get(mlxsw_pci, dqn);
+ mlxsw_pci_cqe_rdq_handle(mlxsw_pci, rdq,
+ wqe_counter, q->cq.v, ncqe);
+
+ if (++items == credits)
+ break;
+ }
- sdq = mlxsw_pci_sdq_get(mlxsw_pci, dqn);
- mlxsw_pci_cqe_sdq_handle(mlxsw_pci, sdq,
- wqe_counter, q->cq.v, ncqe);
- } else {
- struct mlxsw_pci_queue *rdq;
+ mlxsw_pci_queue_doorbell_arm_consumer_ring(mlxsw_pci, q);
+}
- rdq = mlxsw_pci_rdq_get(mlxsw_pci, dqn);
- mlxsw_pci_cqe_rdq_handle(mlxsw_pci, rdq,
- wqe_counter, q->cq.v, ncqe);
+static void mlxsw_pci_cq_tx_tasklet(struct tasklet_struct *t)
+{
+ struct mlxsw_pci_queue *q = from_tasklet(q, t, tasklet);
+ struct mlxsw_pci *mlxsw_pci = q->pci;
+ int credits = q->count >> 1;
+ int items = 0;
+ char *cqe;
+
+ while ((cqe = mlxsw_pci_cq_sw_cqe_get(q))) {
+ u16 wqe_counter = mlxsw_pci_cqe_wqe_counter_get(cqe);
+ u8 sendq = mlxsw_pci_cqe_sr_get(q->cq.v, cqe);
+ u8 dqn = mlxsw_pci_cqe_dqn_get(q->cq.v, cqe);
+ char ncqe[MLXSW_PCI_CQE_SIZE_MAX];
+ struct mlxsw_pci_queue *sdq;
+
+ if (unlikely(!sendq)) {
+ WARN_ON_ONCE(1);
+ continue;
}
+
+ memcpy(ncqe, cqe, q->elem_size);
+ mlxsw_pci_queue_doorbell_consumer_ring(mlxsw_pci, q);
+
+ sdq = mlxsw_pci_sdq_get(mlxsw_pci, dqn);
+ mlxsw_pci_cqe_sdq_handle(mlxsw_pci, sdq,
+ wqe_counter, q->cq.v, ncqe);
+
if (++items == credits)
break;
}
mlxsw_pci_queue_doorbell_arm_consumer_ring(mlxsw_pci, q);
}
+static enum mlxsw_pci_cq_type
+mlxsw_pci_cq_type(const struct mlxsw_pci *mlxsw_pci,
+ const struct mlxsw_pci_queue *q)
+{
+ /* Each CQ is mapped to one DQ. The first 'num_sdq_cqs' queues are used
+ * for SDQs and the rest are used for RDQs.
+ */
+ if (q->num < mlxsw_pci->num_sdq_cqs)
+ return MLXSW_PCI_CQ_SDQ;
+
+ return MLXSW_PCI_CQ_RDQ;
+}
+
+static void mlxsw_pci_cq_tasklet_setup(struct mlxsw_pci_queue *q,
+ enum mlxsw_pci_cq_type cq_type)
+{
+ switch (cq_type) {
+ case MLXSW_PCI_CQ_SDQ:
+ tasklet_setup(&q->tasklet, mlxsw_pci_cq_tx_tasklet);
+ break;
+ case MLXSW_PCI_CQ_RDQ:
+ tasklet_setup(&q->tasklet, mlxsw_pci_cq_rx_tasklet);
+ break;
+ }
+}
+
static int mlxsw_pci_cq_init(struct mlxsw_pci *mlxsw_pci, char *mbox,
struct mlxsw_pci_queue *q)
{
err = mlxsw_cmd_sw2hw_cq(mlxsw_pci->core, mbox, q->num);
if (err)
return err;
- tasklet_setup(&q->tasklet, mlxsw_pci_cq_tasklet);
+ mlxsw_pci_cq_tasklet_setup(q, mlxsw_pci_cq_type(mlxsw_pci, q));
mlxsw_pci_queue_doorbell_consumer_ring(mlxsw_pci, q);
mlxsw_pci_queue_doorbell_arm_consumer_ring(mlxsw_pci, q);
return 0;