13f3a1675SAlvaro Karsz // SPDX-License-Identifier: GPL-2.0-only 23f3a1675SAlvaro Karsz /* 33f3a1675SAlvaro Karsz * SolidRun DPU driver for control plane 43f3a1675SAlvaro Karsz * 53f3a1675SAlvaro Karsz * Copyright (C) 2022-2023 SolidRun 63f3a1675SAlvaro Karsz * 73f3a1675SAlvaro Karsz * Author: Alvaro Karsz <alvaro.karsz@solid-run.com> 83f3a1675SAlvaro Karsz * 93f3a1675SAlvaro Karsz */ 103f3a1675SAlvaro Karsz 113f3a1675SAlvaro Karsz #include <linux/iopoll.h> 123f3a1675SAlvaro Karsz 133f3a1675SAlvaro Karsz #include "snet_vdpa.h" 143f3a1675SAlvaro Karsz 153f3a1675SAlvaro Karsz enum snet_ctrl_opcodes { 163f3a1675SAlvaro Karsz SNET_CTRL_OP_DESTROY = 1, 173f3a1675SAlvaro Karsz SNET_CTRL_OP_READ_VQ_STATE, 18*3616bf37SAlvaro Karsz SNET_CTRL_OP_SUSPEND, 193f3a1675SAlvaro Karsz }; 203f3a1675SAlvaro Karsz 213f3a1675SAlvaro Karsz #define SNET_CTRL_TIMEOUT 2000000 223f3a1675SAlvaro Karsz 233f3a1675SAlvaro Karsz #define SNET_CTRL_DATA_SIZE_MASK 0x0000FFFF 243f3a1675SAlvaro Karsz #define SNET_CTRL_IN_PROCESS_MASK 0x00010000 253f3a1675SAlvaro Karsz #define SNET_CTRL_CHUNK_RDY_MASK 0x00020000 263f3a1675SAlvaro Karsz #define SNET_CTRL_ERROR_MASK 0x0FFC0000 273f3a1675SAlvaro Karsz 283f3a1675SAlvaro Karsz #define SNET_VAL_TO_ERR(val) (-(((val) & SNET_CTRL_ERROR_MASK) >> 18)) 293f3a1675SAlvaro Karsz #define SNET_EMPTY_CTRL(val) (((val) & SNET_CTRL_ERROR_MASK) || \ 303f3a1675SAlvaro Karsz !((val) & SNET_CTRL_IN_PROCESS_MASK)) 313f3a1675SAlvaro Karsz #define SNET_DATA_READY(val) ((val) & (SNET_CTRL_ERROR_MASK | SNET_CTRL_CHUNK_RDY_MASK)) 323f3a1675SAlvaro Karsz 333f3a1675SAlvaro Karsz /* Control register used to read data from the DPU */ 343f3a1675SAlvaro Karsz struct snet_ctrl_reg_ctrl { 353f3a1675SAlvaro Karsz /* Chunk size in 4B words */ 363f3a1675SAlvaro Karsz u16 data_size; 373f3a1675SAlvaro Karsz /* We are in the middle of a command */ 383f3a1675SAlvaro Karsz u16 in_process:1; 393f3a1675SAlvaro Karsz /* A data chunk is ready and can be consumed */ 403f3a1675SAlvaro Karsz u16 chunk_ready:1; 413f3a1675SAlvaro Karsz /* Error code */ 423f3a1675SAlvaro Karsz u16 error:10; 433f3a1675SAlvaro Karsz /* Saved for future usage */ 443f3a1675SAlvaro Karsz u16 rsvd:4; 453f3a1675SAlvaro Karsz }; 463f3a1675SAlvaro Karsz 473f3a1675SAlvaro Karsz /* Opcode register */ 483f3a1675SAlvaro Karsz struct snet_ctrl_reg_op { 493f3a1675SAlvaro Karsz u16 opcode; 503f3a1675SAlvaro Karsz /* Only if VQ index is relevant for the command */ 513f3a1675SAlvaro Karsz u16 vq_idx; 523f3a1675SAlvaro Karsz }; 533f3a1675SAlvaro Karsz 543f3a1675SAlvaro Karsz struct snet_ctrl_regs { 553f3a1675SAlvaro Karsz struct snet_ctrl_reg_op op; 563f3a1675SAlvaro Karsz struct snet_ctrl_reg_ctrl ctrl; 573f3a1675SAlvaro Karsz u32 rsvd; 583f3a1675SAlvaro Karsz u32 data[]; 593f3a1675SAlvaro Karsz }; 603f3a1675SAlvaro Karsz 613f3a1675SAlvaro Karsz static struct snet_ctrl_regs __iomem *snet_get_ctrl(struct snet *snet) 623f3a1675SAlvaro Karsz { 633f3a1675SAlvaro Karsz return snet->bar + snet->psnet->cfg.ctrl_off; 643f3a1675SAlvaro Karsz } 653f3a1675SAlvaro Karsz 663f3a1675SAlvaro Karsz static int snet_wait_for_empty_ctrl(struct snet_ctrl_regs __iomem *regs) 673f3a1675SAlvaro Karsz { 683f3a1675SAlvaro Karsz u32 val; 693f3a1675SAlvaro Karsz 703f3a1675SAlvaro Karsz return readx_poll_timeout(ioread32, ®s->ctrl, val, SNET_EMPTY_CTRL(val), 10, 713f3a1675SAlvaro Karsz SNET_CTRL_TIMEOUT); 723f3a1675SAlvaro Karsz } 733f3a1675SAlvaro Karsz 743f3a1675SAlvaro Karsz static int snet_wait_for_empty_op(struct snet_ctrl_regs __iomem *regs) 753f3a1675SAlvaro Karsz { 763f3a1675SAlvaro Karsz u32 val; 773f3a1675SAlvaro Karsz 783f3a1675SAlvaro Karsz return readx_poll_timeout(ioread32, ®s->op, val, !val, 10, SNET_CTRL_TIMEOUT); 793f3a1675SAlvaro Karsz } 803f3a1675SAlvaro Karsz 813f3a1675SAlvaro Karsz static int snet_wait_for_data(struct snet_ctrl_regs __iomem *regs) 823f3a1675SAlvaro Karsz { 833f3a1675SAlvaro Karsz u32 val; 843f3a1675SAlvaro Karsz 853f3a1675SAlvaro Karsz return readx_poll_timeout(ioread32, ®s->ctrl, val, SNET_DATA_READY(val), 10, 863f3a1675SAlvaro Karsz SNET_CTRL_TIMEOUT); 873f3a1675SAlvaro Karsz } 883f3a1675SAlvaro Karsz 893f3a1675SAlvaro Karsz static u32 snet_read32_word(struct snet_ctrl_regs __iomem *ctrl_regs, u16 word_idx) 903f3a1675SAlvaro Karsz { 913f3a1675SAlvaro Karsz return ioread32(&ctrl_regs->data[word_idx]); 923f3a1675SAlvaro Karsz } 933f3a1675SAlvaro Karsz 943f3a1675SAlvaro Karsz static u32 snet_read_ctrl(struct snet_ctrl_regs __iomem *ctrl_regs) 953f3a1675SAlvaro Karsz { 963f3a1675SAlvaro Karsz return ioread32(&ctrl_regs->ctrl); 973f3a1675SAlvaro Karsz } 983f3a1675SAlvaro Karsz 993f3a1675SAlvaro Karsz static void snet_write_ctrl(struct snet_ctrl_regs __iomem *ctrl_regs, u32 val) 1003f3a1675SAlvaro Karsz { 1013f3a1675SAlvaro Karsz iowrite32(val, &ctrl_regs->ctrl); 1023f3a1675SAlvaro Karsz } 1033f3a1675SAlvaro Karsz 1043f3a1675SAlvaro Karsz static void snet_write_op(struct snet_ctrl_regs __iomem *ctrl_regs, u32 val) 1053f3a1675SAlvaro Karsz { 1063f3a1675SAlvaro Karsz iowrite32(val, &ctrl_regs->op); 1073f3a1675SAlvaro Karsz } 1083f3a1675SAlvaro Karsz 1093f3a1675SAlvaro Karsz static int snet_wait_for_dpu_completion(struct snet_ctrl_regs __iomem *ctrl_regs) 1103f3a1675SAlvaro Karsz { 1113f3a1675SAlvaro Karsz /* Wait until the DPU finishes completely. 1123f3a1675SAlvaro Karsz * It will clear the opcode register. 1133f3a1675SAlvaro Karsz */ 1143f3a1675SAlvaro Karsz return snet_wait_for_empty_op(ctrl_regs); 1153f3a1675SAlvaro Karsz } 1163f3a1675SAlvaro Karsz 1173f3a1675SAlvaro Karsz /* Reading ctrl from the DPU: 1183f3a1675SAlvaro Karsz * buf_size must be 4B aligned 1193f3a1675SAlvaro Karsz * 1203f3a1675SAlvaro Karsz * Steps: 1213f3a1675SAlvaro Karsz * 1223f3a1675SAlvaro Karsz * (1) Verify that the DPU is not in the middle of another operation by 1233f3a1675SAlvaro Karsz * reading the in_process and error bits in the control register. 1243f3a1675SAlvaro Karsz * (2) Write the request opcode and the VQ idx in the opcode register 1253f3a1675SAlvaro Karsz * and write the buffer size in the control register. 1263f3a1675SAlvaro Karsz * (3) Start readind chunks of data, chunk_ready bit indicates that a 1273f3a1675SAlvaro Karsz * data chunk is available, we signal that we read the data by clearing the bit. 1283f3a1675SAlvaro Karsz * (4) Detect that the transfer is completed when the in_process bit 1293f3a1675SAlvaro Karsz * in the control register is cleared or when the an error appears. 1303f3a1675SAlvaro Karsz */ 1313f3a1675SAlvaro Karsz static int snet_ctrl_read_from_dpu(struct snet *snet, u16 opcode, u16 vq_idx, void *buffer, 1323f3a1675SAlvaro Karsz u32 buf_size) 1333f3a1675SAlvaro Karsz { 1343f3a1675SAlvaro Karsz struct pci_dev *pdev = snet->pdev; 1353f3a1675SAlvaro Karsz struct snet_ctrl_regs __iomem *regs = snet_get_ctrl(snet); 1363f3a1675SAlvaro Karsz u32 *bfr_ptr = (u32 *)buffer; 1373f3a1675SAlvaro Karsz u32 val; 1383f3a1675SAlvaro Karsz u16 buf_words; 1393f3a1675SAlvaro Karsz int ret; 1403f3a1675SAlvaro Karsz u16 words, i, tot_words = 0; 1413f3a1675SAlvaro Karsz 1423f3a1675SAlvaro Karsz /* Supported for config 2+ */ 1433f3a1675SAlvaro Karsz if (!SNET_CFG_VER(snet, 2)) 1443f3a1675SAlvaro Karsz return -EOPNOTSUPP; 1453f3a1675SAlvaro Karsz 1463f3a1675SAlvaro Karsz if (!IS_ALIGNED(buf_size, 4)) 1473f3a1675SAlvaro Karsz return -EINVAL; 1483f3a1675SAlvaro Karsz 1493f3a1675SAlvaro Karsz mutex_lock(&snet->ctrl_lock); 1503f3a1675SAlvaro Karsz 1513f3a1675SAlvaro Karsz buf_words = buf_size / 4; 1523f3a1675SAlvaro Karsz 1533f3a1675SAlvaro Karsz /* Make sure control register is empty */ 1543f3a1675SAlvaro Karsz ret = snet_wait_for_empty_ctrl(regs); 1553f3a1675SAlvaro Karsz if (ret) { 1563f3a1675SAlvaro Karsz SNET_WARN(pdev, "Timeout waiting for previous control data to be consumed\n"); 1573f3a1675SAlvaro Karsz goto exit; 1583f3a1675SAlvaro Karsz } 1593f3a1675SAlvaro Karsz 1603f3a1675SAlvaro Karsz /* We need to write the buffer size in the control register, and the opcode + vq index in 1613f3a1675SAlvaro Karsz * the opcode register. 1623f3a1675SAlvaro Karsz * We use a spinlock to serialize the writes. 1633f3a1675SAlvaro Karsz */ 1643f3a1675SAlvaro Karsz spin_lock(&snet->ctrl_spinlock); 1653f3a1675SAlvaro Karsz 1663f3a1675SAlvaro Karsz snet_write_ctrl(regs, buf_words); 1673f3a1675SAlvaro Karsz snet_write_op(regs, opcode | (vq_idx << 16)); 1683f3a1675SAlvaro Karsz 1693f3a1675SAlvaro Karsz spin_unlock(&snet->ctrl_spinlock); 1703f3a1675SAlvaro Karsz 1713f3a1675SAlvaro Karsz while (buf_words != tot_words) { 1723f3a1675SAlvaro Karsz ret = snet_wait_for_data(regs); 1733f3a1675SAlvaro Karsz if (ret) { 1743f3a1675SAlvaro Karsz SNET_WARN(pdev, "Timeout waiting for control data\n"); 1753f3a1675SAlvaro Karsz goto exit; 1763f3a1675SAlvaro Karsz } 1773f3a1675SAlvaro Karsz 1783f3a1675SAlvaro Karsz val = snet_read_ctrl(regs); 1793f3a1675SAlvaro Karsz 1803f3a1675SAlvaro Karsz /* Error? */ 1813f3a1675SAlvaro Karsz if (val & SNET_CTRL_ERROR_MASK) { 1823f3a1675SAlvaro Karsz ret = SNET_VAL_TO_ERR(val); 1833f3a1675SAlvaro Karsz SNET_WARN(pdev, "Error while reading control data from DPU, err %d\n", ret); 1843f3a1675SAlvaro Karsz goto exit; 1853f3a1675SAlvaro Karsz } 1863f3a1675SAlvaro Karsz 1873f3a1675SAlvaro Karsz words = min_t(u16, val & SNET_CTRL_DATA_SIZE_MASK, buf_words - tot_words); 1883f3a1675SAlvaro Karsz 1893f3a1675SAlvaro Karsz for (i = 0; i < words; i++) { 1903f3a1675SAlvaro Karsz *bfr_ptr = snet_read32_word(regs, i); 1913f3a1675SAlvaro Karsz bfr_ptr++; 1923f3a1675SAlvaro Karsz } 1933f3a1675SAlvaro Karsz 1943f3a1675SAlvaro Karsz tot_words += words; 1953f3a1675SAlvaro Karsz 1963f3a1675SAlvaro Karsz /* Is the job completed? */ 1973f3a1675SAlvaro Karsz if (!(val & SNET_CTRL_IN_PROCESS_MASK)) 1983f3a1675SAlvaro Karsz break; 1993f3a1675SAlvaro Karsz 2003f3a1675SAlvaro Karsz /* Clear the chunk ready bit and continue */ 2013f3a1675SAlvaro Karsz val &= ~SNET_CTRL_CHUNK_RDY_MASK; 2023f3a1675SAlvaro Karsz snet_write_ctrl(regs, val); 2033f3a1675SAlvaro Karsz } 2043f3a1675SAlvaro Karsz 2053f3a1675SAlvaro Karsz ret = snet_wait_for_dpu_completion(regs); 2063f3a1675SAlvaro Karsz if (ret) 2073f3a1675SAlvaro Karsz SNET_WARN(pdev, "Timeout waiting for the DPU to complete a control command\n"); 2083f3a1675SAlvaro Karsz 2093f3a1675SAlvaro Karsz exit: 2103f3a1675SAlvaro Karsz mutex_unlock(&snet->ctrl_lock); 2113f3a1675SAlvaro Karsz return ret; 2123f3a1675SAlvaro Karsz } 2133f3a1675SAlvaro Karsz 2143f3a1675SAlvaro Karsz /* Send a control message to the DPU using the old mechanism 2153f3a1675SAlvaro Karsz * used with config version 1. 2163f3a1675SAlvaro Karsz */ 2173f3a1675SAlvaro Karsz static int snet_send_ctrl_msg_old(struct snet *snet, u32 opcode) 2183f3a1675SAlvaro Karsz { 2193f3a1675SAlvaro Karsz struct pci_dev *pdev = snet->pdev; 2203f3a1675SAlvaro Karsz struct snet_ctrl_regs __iomem *regs = snet_get_ctrl(snet); 2213f3a1675SAlvaro Karsz int ret; 2223f3a1675SAlvaro Karsz 2233f3a1675SAlvaro Karsz mutex_lock(&snet->ctrl_lock); 2243f3a1675SAlvaro Karsz 2253f3a1675SAlvaro Karsz /* Old mechanism uses just 1 register, the opcode register. 2263f3a1675SAlvaro Karsz * Make sure that the opcode register is empty, and that the DPU isn't 2273f3a1675SAlvaro Karsz * processing an old message. 2283f3a1675SAlvaro Karsz */ 2293f3a1675SAlvaro Karsz ret = snet_wait_for_empty_op(regs); 2303f3a1675SAlvaro Karsz if (ret) { 2313f3a1675SAlvaro Karsz SNET_WARN(pdev, "Timeout waiting for previous control message to be ACKed\n"); 2323f3a1675SAlvaro Karsz goto exit; 2333f3a1675SAlvaro Karsz } 2343f3a1675SAlvaro Karsz 2353f3a1675SAlvaro Karsz /* Write the message */ 2363f3a1675SAlvaro Karsz snet_write_op(regs, opcode); 2373f3a1675SAlvaro Karsz 2383f3a1675SAlvaro Karsz /* DPU ACKs the message by clearing the opcode register */ 2393f3a1675SAlvaro Karsz ret = snet_wait_for_empty_op(regs); 2403f3a1675SAlvaro Karsz if (ret) 2413f3a1675SAlvaro Karsz SNET_WARN(pdev, "Timeout waiting for a control message to be ACKed\n"); 2423f3a1675SAlvaro Karsz 2433f3a1675SAlvaro Karsz exit: 2443f3a1675SAlvaro Karsz mutex_unlock(&snet->ctrl_lock); 2453f3a1675SAlvaro Karsz return ret; 2463f3a1675SAlvaro Karsz } 2473f3a1675SAlvaro Karsz 2483f3a1675SAlvaro Karsz /* Send a control message to the DPU. 2493f3a1675SAlvaro Karsz * A control message is a message without payload. 2503f3a1675SAlvaro Karsz */ 2513f3a1675SAlvaro Karsz static int snet_send_ctrl_msg(struct snet *snet, u16 opcode, u16 vq_idx) 2523f3a1675SAlvaro Karsz { 2533f3a1675SAlvaro Karsz struct pci_dev *pdev = snet->pdev; 2543f3a1675SAlvaro Karsz struct snet_ctrl_regs __iomem *regs = snet_get_ctrl(snet); 2553f3a1675SAlvaro Karsz u32 val; 2563f3a1675SAlvaro Karsz int ret; 2573f3a1675SAlvaro Karsz 2583f3a1675SAlvaro Karsz /* If config version is not 2+, use the old mechanism */ 2593f3a1675SAlvaro Karsz if (!SNET_CFG_VER(snet, 2)) 2603f3a1675SAlvaro Karsz return snet_send_ctrl_msg_old(snet, opcode); 2613f3a1675SAlvaro Karsz 2623f3a1675SAlvaro Karsz mutex_lock(&snet->ctrl_lock); 2633f3a1675SAlvaro Karsz 2643f3a1675SAlvaro Karsz /* Make sure control register is empty */ 2653f3a1675SAlvaro Karsz ret = snet_wait_for_empty_ctrl(regs); 2663f3a1675SAlvaro Karsz if (ret) { 2673f3a1675SAlvaro Karsz SNET_WARN(pdev, "Timeout waiting for previous control data to be consumed\n"); 2683f3a1675SAlvaro Karsz goto exit; 2693f3a1675SAlvaro Karsz } 2703f3a1675SAlvaro Karsz 2713f3a1675SAlvaro Karsz /* We need to clear the control register and write the opcode + vq index in the opcode 2723f3a1675SAlvaro Karsz * register. 2733f3a1675SAlvaro Karsz * We use a spinlock to serialize the writes. 2743f3a1675SAlvaro Karsz */ 2753f3a1675SAlvaro Karsz spin_lock(&snet->ctrl_spinlock); 2763f3a1675SAlvaro Karsz 2773f3a1675SAlvaro Karsz snet_write_ctrl(regs, 0); 2783f3a1675SAlvaro Karsz snet_write_op(regs, opcode | (vq_idx << 16)); 2793f3a1675SAlvaro Karsz 2803f3a1675SAlvaro Karsz spin_unlock(&snet->ctrl_spinlock); 2813f3a1675SAlvaro Karsz 2823f3a1675SAlvaro Karsz /* The DPU ACKs control messages by setting the chunk ready bit 2833f3a1675SAlvaro Karsz * without data. 2843f3a1675SAlvaro Karsz */ 2853f3a1675SAlvaro Karsz ret = snet_wait_for_data(regs); 2863f3a1675SAlvaro Karsz if (ret) { 2873f3a1675SAlvaro Karsz SNET_WARN(pdev, "Timeout waiting for control message to be ACKed\n"); 2883f3a1675SAlvaro Karsz goto exit; 2893f3a1675SAlvaro Karsz } 2903f3a1675SAlvaro Karsz 2913f3a1675SAlvaro Karsz /* Check for errors */ 2923f3a1675SAlvaro Karsz val = snet_read_ctrl(regs); 2933f3a1675SAlvaro Karsz ret = SNET_VAL_TO_ERR(val); 2943f3a1675SAlvaro Karsz 2953f3a1675SAlvaro Karsz /* Clear the chunk ready bit */ 2963f3a1675SAlvaro Karsz val &= ~SNET_CTRL_CHUNK_RDY_MASK; 2973f3a1675SAlvaro Karsz snet_write_ctrl(regs, val); 2983f3a1675SAlvaro Karsz 2993f3a1675SAlvaro Karsz ret = snet_wait_for_dpu_completion(regs); 3003f3a1675SAlvaro Karsz if (ret) 3013f3a1675SAlvaro Karsz SNET_WARN(pdev, "Timeout waiting for DPU to complete a control command, err %d\n", 3023f3a1675SAlvaro Karsz ret); 3033f3a1675SAlvaro Karsz 3043f3a1675SAlvaro Karsz exit: 3053f3a1675SAlvaro Karsz mutex_unlock(&snet->ctrl_lock); 3063f3a1675SAlvaro Karsz return ret; 3073f3a1675SAlvaro Karsz } 3083f3a1675SAlvaro Karsz 3093f3a1675SAlvaro Karsz void snet_ctrl_clear(struct snet *snet) 3103f3a1675SAlvaro Karsz { 3113f3a1675SAlvaro Karsz struct snet_ctrl_regs __iomem *regs = snet_get_ctrl(snet); 3123f3a1675SAlvaro Karsz 3133f3a1675SAlvaro Karsz snet_write_op(regs, 0); 3143f3a1675SAlvaro Karsz } 3153f3a1675SAlvaro Karsz 3163f3a1675SAlvaro Karsz int snet_destroy_dev(struct snet *snet) 3173f3a1675SAlvaro Karsz { 3183f3a1675SAlvaro Karsz return snet_send_ctrl_msg(snet, SNET_CTRL_OP_DESTROY, 0); 3193f3a1675SAlvaro Karsz } 3203f3a1675SAlvaro Karsz 3213f3a1675SAlvaro Karsz int snet_read_vq_state(struct snet *snet, u16 idx, struct vdpa_vq_state *state) 3223f3a1675SAlvaro Karsz { 3233f3a1675SAlvaro Karsz return snet_ctrl_read_from_dpu(snet, SNET_CTRL_OP_READ_VQ_STATE, idx, state, 3243f3a1675SAlvaro Karsz sizeof(*state)); 3253f3a1675SAlvaro Karsz } 326*3616bf37SAlvaro Karsz 327*3616bf37SAlvaro Karsz int snet_suspend_dev(struct snet *snet) 328*3616bf37SAlvaro Karsz { 329*3616bf37SAlvaro Karsz return snet_send_ctrl_msg(snet, SNET_CTRL_OP_SUSPEND, 0); 330*3616bf37SAlvaro Karsz } 331