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