diff options
Diffstat (limited to 'drivers/vdpa/solidrun/snet_main.c')
| -rw-r--r-- | drivers/vdpa/solidrun/snet_main.c | 146 | 
1 files changed, 76 insertions, 70 deletions
diff --git a/drivers/vdpa/solidrun/snet_main.c b/drivers/vdpa/solidrun/snet_main.c index 68de727398ed..cdcd84ce4f5a 100644 --- a/drivers/vdpa/solidrun/snet_main.c +++ b/drivers/vdpa/solidrun/snet_main.c @@ -2,7 +2,7 @@  /*   * SolidRun DPU driver for control plane   * - * Copyright (C) 2022 SolidRun + * Copyright (C) 2022-2023 SolidRun   *   * Author: Alvaro Karsz <[email protected]>   * @@ -16,14 +16,12 @@  /* SNET signature */  #define SNET_SIGNATURE          0xD0D06363  /* Max. config version that we can work with */ -#define SNET_CFG_VERSION        0x1 +#define SNET_CFG_VERSION        0x2  /* Queue align */  #define SNET_QUEUE_ALIGNMENT    PAGE_SIZE  /* Kick value to notify that new data is available */  #define SNET_KICK_VAL           0x1  #define SNET_CONFIG_OFF         0x0 -/* ACK timeout for a message */ -#define SNET_ACK_TIMEOUT	2000000  /* How long we are willing to wait for a SNET device */  #define SNET_DETECT_TIMEOUT	5000000  /* How long should we wait for the DPU to read our config */ @@ -32,61 +30,16 @@  #define SNET_GENERAL_CFG_LEN	36  #define SNET_GENERAL_CFG_VQ_LEN	40 -enum snet_msg { -	SNET_MSG_DESTROY = 1, -}; -  static struct snet *vdpa_to_snet(struct vdpa_device *vdpa)  {  	return container_of(vdpa, struct snet, vdpa);  } -static int snet_wait_for_msg_ack(struct snet *snet) -{ -	struct pci_dev *pdev = snet->pdev; -	int ret; -	u32 val; - -	/* The DPU will clear the messages offset once messages -	 * are processed. -	 */ -	ret = readx_poll_timeout(ioread32, snet->bar + snet->psnet->cfg.msg_off, -				 val, !val, 10, SNET_ACK_TIMEOUT); -	if (ret) -		SNET_WARN(pdev, "Timeout waiting for message ACK\n"); - -	return ret; -} - -/* Sends a message to the DPU. - * If blocking is set, the function will return once the - * message was processed by the DPU (or timeout). - */ -static int snet_send_msg(struct snet *snet, u32 msg, bool blocking) -{ -	int ret = 0; - -	/* Make sure the DPU acked last message before issuing a new one */ -	ret = snet_wait_for_msg_ack(snet); -	if (ret) -		return ret; - -	/* Write the message */ -	snet_write32(snet, snet->psnet->cfg.msg_off, msg); - -	if (blocking) -		ret = snet_wait_for_msg_ack(snet); -	else /* If non-blocking, flush the write by issuing a read */ -		snet_read32(snet, snet->psnet->cfg.msg_off); - -	return ret; -} -  static irqreturn_t snet_cfg_irq_hndlr(int irq, void *data)  {  	struct snet *snet = data;  	/* Call callback if any */ -	if (snet->cb.callback) +	if (likely(snet->cb.callback))  		return snet->cb.callback(snet->cb.private);  	return IRQ_HANDLED; @@ -96,7 +49,7 @@ static irqreturn_t snet_vq_irq_hndlr(int irq, void *data)  {  	struct snet_vq *vq = data;  	/* Call callback if any */ -	if (vq->cb.callback) +	if (likely(vq->cb.callback))  		return vq->cb.callback(vq->cb.private);  	return IRQ_HANDLED; @@ -153,12 +106,24 @@ static void snet_kick_vq(struct vdpa_device *vdev, u16 idx)  {  	struct snet *snet = vdpa_to_snet(vdev);  	/* not ready - ignore */ -	if (!snet->vqs[idx]->ready) +	if (unlikely(!snet->vqs[idx]->ready))  		return;  	iowrite32(SNET_KICK_VAL, snet->vqs[idx]->kick_ptr);  } +static void snet_kick_vq_with_data(struct vdpa_device *vdev, u32 data) +{ +	struct snet *snet = vdpa_to_snet(vdev); +	u16 idx = data & 0xFFFF; + +	/* not ready - ignore */ +	if (unlikely(!snet->vqs[idx]->ready)) +		return; + +	iowrite32((data & 0xFFFF0000) | SNET_KICK_VAL, snet->vqs[idx]->kick_ptr); +} +  static void snet_set_vq_cb(struct vdpa_device *vdev, u16 idx, struct vdpa_callback *cb)  {  	struct snet *snet = vdpa_to_snet(vdev); @@ -181,33 +146,48 @@ static bool snet_get_vq_ready(struct vdpa_device *vdev, u16 idx)  	return snet->vqs[idx]->ready;  } -static int snet_set_vq_state(struct vdpa_device *vdev, u16 idx, const struct vdpa_vq_state *state) +static bool snet_vq_state_is_initial(struct snet *snet, const struct vdpa_vq_state *state)  { -	struct snet *snet = vdpa_to_snet(vdev); -	/* Setting the VQ state is not supported. -	 * If the asked state is the same as the initial one -	 * we can ignore it. -	 */  	if (SNET_HAS_FEATURE(snet, VIRTIO_F_RING_PACKED)) {  		const struct vdpa_vq_state_packed *p = &state->packed;  		if (p->last_avail_counter == 1 && p->last_used_counter == 1 &&  		    p->last_avail_idx == 0 && p->last_used_idx == 0) -			return 0; +			return true;  	} else {  		const struct vdpa_vq_state_split *s = &state->split;  		if (s->avail_index == 0) -			return 0; +			return true;  	} +	return false; +} + +static int snet_set_vq_state(struct vdpa_device *vdev, u16 idx, const struct vdpa_vq_state *state) +{ +	struct snet *snet = vdpa_to_snet(vdev); + +	/* We can set any state for config version 2+ */ +	if (SNET_CFG_VER(snet, 2)) { +		memcpy(&snet->vqs[idx]->vq_state, state, sizeof(*state)); +		return 0; +	} + +	/* Older config - we can't set the VQ state. +	 * Return 0 only if this is the initial state we use in the DPU. +	 */ +	if (snet_vq_state_is_initial(snet, state)) +		return 0; +  	return -EOPNOTSUPP;  }  static int snet_get_vq_state(struct vdpa_device *vdev, u16 idx, struct vdpa_vq_state *state)  { -	/* Not supported */ -	return -EOPNOTSUPP; +	struct snet *snet = vdpa_to_snet(vdev); + +	return snet_read_vq_state(snet, idx, state);  }  static int snet_get_vq_irq(struct vdpa_device *vdev, u16 idx) @@ -232,9 +212,9 @@ static int snet_reset_dev(struct snet *snet)  	if (!snet->status)  		return 0; -	/* If DPU started, send a destroy message */ +	/* If DPU started, destroy it */  	if (snet->status & VIRTIO_CONFIG_S_DRIVER_OK) -		ret = snet_send_msg(snet, SNET_MSG_DESTROY, true); +		ret = snet_destroy_dev(snet);  	/* Clear VQs */  	for (i = 0; i < snet->cfg->vq_num; i++) { @@ -258,7 +238,7 @@ static int snet_reset_dev(struct snet *snet)  	snet->dpu_ready = false;  	if (ret) -		SNET_WARN(pdev, "Incomplete reset to SNET[%u] device\n", snet->sid); +		SNET_WARN(pdev, "Incomplete reset to SNET[%u] device, err: %d\n", snet->sid, ret);  	else  		SNET_DBG(pdev, "Reset SNET[%u] device\n", snet->sid); @@ -356,7 +336,7 @@ static int snet_write_conf(struct snet *snet)  	 * |             DESC AREA                |  	 * |            DEVICE AREA               |  	 * |            DRIVER AREA               | -	 * |             RESERVED                 | +	 * |    VQ STATE (CFG 2+)     |   RSVD    |  	 *  	 * Magic number should be written last, this is the DPU indication that the data is ready  	 */ @@ -391,12 +371,15 @@ static int snet_write_conf(struct snet *snet)  		off += 8;  		snet_write64(snet, off, snet->vqs[i]->driver_area);  		off += 8; +		/* Write VQ state if config version is 2+ */ +		if (SNET_CFG_VER(snet, 2)) +			snet_write32(snet, off, *(u32 *)&snet->vqs[i]->vq_state); +		off += 4; +  		/* Ignore reserved */ -		off += 8; +		off += 4;  	} -	/* Clear snet messages address for this device */ -	snet_write32(snet, snet->psnet->cfg.msg_off, 0);  	/* Write magic number - data is ready */  	snet_write32(snet, snet->psnet->cfg.host_cfg_off, SNET_SIGNATURE); @@ -512,10 +495,25 @@ static void snet_set_config(struct vdpa_device *vdev, unsigned int offset,  		iowrite8(*buf_ptr++, cfg_ptr + i);  } +static int snet_suspend(struct vdpa_device *vdev) +{ +	struct snet *snet = vdpa_to_snet(vdev); +	int ret; + +	ret = snet_suspend_dev(snet); +	if (ret) +		SNET_ERR(snet->pdev, "SNET[%u] suspend failed, err: %d\n", snet->sid, ret); +	else +		SNET_DBG(snet->pdev, "Suspend SNET[%u] device\n", snet->sid); + +	return ret; +} +  static const struct vdpa_config_ops snet_config_ops = {  	.set_vq_address         = snet_set_vq_address,  	.set_vq_num             = snet_set_vq_num,  	.kick_vq                = snet_kick_vq, +	.kick_vq_with_data	= snet_kick_vq_with_data,  	.set_vq_cb              = snet_set_vq_cb,  	.set_vq_ready           = snet_set_vq_ready,  	.get_vq_ready           = snet_get_vq_ready, @@ -537,6 +535,7 @@ static const struct vdpa_config_ops snet_config_ops = {  	.set_status             = snet_set_status,  	.get_config             = snet_get_config,  	.set_config             = snet_set_config, +	.suspend		= snet_suspend,  };  static int psnet_open_pf_bar(struct pci_dev *pdev, struct psnet *psnet) @@ -697,7 +696,7 @@ static int psnet_read_cfg(struct pci_dev *pdev, struct psnet *psnet)  	off += 4;  	cfg->hwmon_off = psnet_read32(psnet, off);  	off += 4; -	cfg->msg_off = psnet_read32(psnet, off); +	cfg->ctrl_off = psnet_read32(psnet, off);  	off += 4;  	cfg->flags = psnet_read32(psnet, off);  	off += 4; @@ -997,6 +996,10 @@ static int snet_vdpa_probe_vf(struct pci_dev *pdev)  		goto free_irqs;  	} +	/* Init control mutex and spinlock */ +	mutex_init(&snet->ctrl_lock); +	spin_lock_init(&snet->ctrl_spinlock); +  	/* Save pci device pointer */  	snet->pdev = pdev;  	snet->psnet = psnet; @@ -1013,6 +1016,9 @@ static int snet_vdpa_probe_vf(struct pci_dev *pdev)  	/* Create a VirtIO config pointer */  	snet->cfg->virtio_cfg = snet->bar + snet->psnet->cfg.virtio_cfg_off; +	/* Clear control registers */ +	snet_ctrl_clear(snet); +  	pci_set_master(pdev);  	pci_set_drvdata(pdev, snet);  |