diff options
Diffstat (limited to 'drivers/platform/mellanox/mlxbf-tmfifo.c')
| -rw-r--r-- | drivers/platform/mellanox/mlxbf-tmfifo.c | 107 | 
1 files changed, 75 insertions, 32 deletions
| diff --git a/drivers/platform/mellanox/mlxbf-tmfifo.c b/drivers/platform/mellanox/mlxbf-tmfifo.c index b600b77d91ef..5c683b4eaf10 100644 --- a/drivers/platform/mellanox/mlxbf-tmfifo.c +++ b/drivers/platform/mellanox/mlxbf-tmfifo.c @@ -53,12 +53,13 @@  struct mlxbf_tmfifo;  /** - * mlxbf_tmfifo_vring - Structure of the TmFifo virtual ring + * struct mlxbf_tmfifo_vring - Structure of the TmFifo virtual ring   * @va: virtual address of the ring   * @dma: dma address of the ring   * @vq: pointer to the virtio virtqueue   * @desc: current descriptor of the pending packet   * @desc_head: head descriptor of the pending packet + * @drop_desc: dummy desc for packet dropping   * @cur_len: processed length of the current descriptor   * @rem_len: remaining length of the pending packet   * @pkt_len: total length of the pending packet @@ -75,6 +76,7 @@ struct mlxbf_tmfifo_vring {  	struct virtqueue *vq;  	struct vring_desc *desc;  	struct vring_desc *desc_head; +	struct vring_desc drop_desc;  	int cur_len;  	int rem_len;  	u32 pkt_len; @@ -86,6 +88,14 @@ struct mlxbf_tmfifo_vring {  	struct mlxbf_tmfifo *fifo;  }; +/* Check whether vring is in drop mode. */ +#define IS_VRING_DROP(_r) ({ \ +	typeof(_r) (r) = (_r); \ +	(r->desc_head == &r->drop_desc ? true : false); }) + +/* A stub length to drop maximum length packet. */ +#define VRING_DROP_DESC_MAX_LEN		GENMASK(15, 0) +  /* Interrupt types. */  enum {  	MLXBF_TM_RX_LWM_IRQ, @@ -103,12 +113,13 @@ enum {  };  /** - * mlxbf_tmfifo_vdev - Structure of the TmFifo virtual device + * struct mlxbf_tmfifo_vdev - Structure of the TmFifo virtual device   * @vdev: virtio device, in which the vdev.id.device field has the   *        VIRTIO_ID_xxx id to distinguish the virtual device.   * @status: status of the device   * @features: supported features of the device   * @vrings: array of tmfifo vrings of this device + * @config: non-anonymous union for cons and net   * @config.cons: virtual console config -   *               select if vdev.id.device is VIRTIO_ID_CONSOLE   * @config.net: virtual network config - @@ -128,7 +139,7 @@ struct mlxbf_tmfifo_vdev {  };  /** - * mlxbf_tmfifo_irq_info - Structure of the interrupt information + * struct mlxbf_tmfifo_irq_info - Structure of the interrupt information   * @fifo: pointer to the tmfifo structure   * @irq: interrupt number   * @index: index into the interrupt array @@ -140,7 +151,7 @@ struct mlxbf_tmfifo_irq_info {  };  /** - * mlxbf_tmfifo_io - Structure of the TmFifo IO resource (for both rx & tx) + * struct mlxbf_tmfifo_io - Structure of the TmFifo IO resource (for both rx & tx)   * @ctl: control register offset (TMFIFO_RX_CTL / TMFIFO_TX_CTL)   * @sts: status register offset (TMFIFO_RX_STS / TMFIFO_TX_STS)   * @data: data register offset (TMFIFO_RX_DATA / TMFIFO_TX_DATA) @@ -152,7 +163,7 @@ struct mlxbf_tmfifo_io {  };  /** - * mlxbf_tmfifo - Structure of the TmFifo + * struct mlxbf_tmfifo - Structure of the TmFifo   * @vdev: array of the virtual devices running over the TmFifo   * @lock: lock to protect the TmFifo access   * @res0: mapped resource block 0 @@ -188,7 +199,7 @@ struct mlxbf_tmfifo {  };  /** - * mlxbf_tmfifo_msg_hdr - Structure of the TmFifo message header + * struct mlxbf_tmfifo_msg_hdr - Structure of the TmFifo message header   * @type: message type   * @len: payload length in network byte order. Messages sent into the FIFO   *       will be read by the other side as data stream in the same byte order. @@ -198,6 +209,7 @@ struct mlxbf_tmfifo {  struct mlxbf_tmfifo_msg_hdr {  	u8 type;  	__be16 len; +	/* private: */  	u8 unused[5];  } __packed __aligned(sizeof(u64)); @@ -214,7 +226,7 @@ static u8 mlxbf_tmfifo_net_default_mac[ETH_ALEN] = {  static efi_char16_t mlxbf_tmfifo_efi_name[] = L"RshimMacAddr";  /* Maximum L2 header length. */ -#define MLXBF_TMFIFO_NET_L2_OVERHEAD	36 +#define MLXBF_TMFIFO_NET_L2_OVERHEAD	(ETH_HLEN + VLAN_HLEN)  /* Supported virtio-net features. */  #define MLXBF_TMFIFO_NET_FEATURES \ @@ -262,6 +274,7 @@ static int mlxbf_tmfifo_alloc_vrings(struct mlxbf_tmfifo *fifo,  		vring->align = SMP_CACHE_BYTES;  		vring->index = i;  		vring->vdev_id = tm_vdev->vdev.id.device; +		vring->drop_desc.len = VRING_DROP_DESC_MAX_LEN;  		dev = &tm_vdev->vdev.dev;  		size = vring_size(vring->num, vring->align); @@ -367,7 +380,7 @@ static u32 mlxbf_tmfifo_get_pkt_len(struct mlxbf_tmfifo_vring *vring,  	return len;  } -static void mlxbf_tmfifo_release_pending_pkt(struct mlxbf_tmfifo_vring *vring) +static void mlxbf_tmfifo_release_pkt(struct mlxbf_tmfifo_vring *vring)  {  	struct vring_desc *desc_head;  	u32 len = 0; @@ -596,19 +609,26 @@ static void mlxbf_tmfifo_rxtx_word(struct mlxbf_tmfifo_vring *vring,  	if (vring->cur_len + sizeof(u64) <= len) {  		/* The whole word. */ -		if (is_rx) -			memcpy(addr + vring->cur_len, &data, sizeof(u64)); -		else -			memcpy(&data, addr + vring->cur_len, sizeof(u64)); +		if (is_rx) { +			if (!IS_VRING_DROP(vring)) +				memcpy(addr + vring->cur_len, &data, +				       sizeof(u64)); +		} else { +			memcpy(&data, addr + vring->cur_len, +			       sizeof(u64)); +		}  		vring->cur_len += sizeof(u64);  	} else {  		/* Leftover bytes. */ -		if (is_rx) -			memcpy(addr + vring->cur_len, &data, -			       len - vring->cur_len); -		else +		if (is_rx) { +			if (!IS_VRING_DROP(vring)) +				memcpy(addr + vring->cur_len, &data, +				       len - vring->cur_len); +		} else { +			data = 0;  			memcpy(&data, addr + vring->cur_len,  			       len - vring->cur_len); +		}  		vring->cur_len = len;  	} @@ -625,13 +645,14 @@ static void mlxbf_tmfifo_rxtx_word(struct mlxbf_tmfifo_vring *vring,   * flag is set.   */  static void mlxbf_tmfifo_rxtx_header(struct mlxbf_tmfifo_vring *vring, -				     struct vring_desc *desc, +				     struct vring_desc **desc,  				     bool is_rx, bool *vring_change)  {  	struct mlxbf_tmfifo *fifo = vring->fifo;  	struct virtio_net_config *config;  	struct mlxbf_tmfifo_msg_hdr hdr;  	int vdev_id, hdr_len; +	bool drop_rx = false;  	/* Read/Write packet header. */  	if (is_rx) { @@ -651,8 +672,8 @@ static void mlxbf_tmfifo_rxtx_header(struct mlxbf_tmfifo_vring *vring,  			if (ntohs(hdr.len) >  			    __virtio16_to_cpu(virtio_legacy_is_little_endian(),  					      config->mtu) + -			    MLXBF_TMFIFO_NET_L2_OVERHEAD) -				return; +					      MLXBF_TMFIFO_NET_L2_OVERHEAD) +				drop_rx = true;  		} else {  			vdev_id = VIRTIO_ID_CONSOLE;  			hdr_len = 0; @@ -667,16 +688,25 @@ static void mlxbf_tmfifo_rxtx_header(struct mlxbf_tmfifo_vring *vring,  			if (!tm_dev2)  				return; -			vring->desc = desc; +			vring->desc = *desc;  			vring = &tm_dev2->vrings[MLXBF_TMFIFO_VRING_RX];  			*vring_change = true;  		} + +		if (drop_rx && !IS_VRING_DROP(vring)) { +			if (vring->desc_head) +				mlxbf_tmfifo_release_pkt(vring); +			*desc = &vring->drop_desc; +			vring->desc_head = *desc; +			vring->desc = *desc; +		} +  		vring->pkt_len = ntohs(hdr.len) + hdr_len;  	} else {  		/* Network virtio has an extra header. */  		hdr_len = (vring->vdev_id == VIRTIO_ID_NET) ?  			   sizeof(struct virtio_net_hdr) : 0; -		vring->pkt_len = mlxbf_tmfifo_get_pkt_len(vring, desc); +		vring->pkt_len = mlxbf_tmfifo_get_pkt_len(vring, *desc);  		hdr.type = (vring->vdev_id == VIRTIO_ID_NET) ?  			    VIRTIO_ID_NET : VIRTIO_ID_CONSOLE;  		hdr.len = htons(vring->pkt_len - hdr_len); @@ -709,15 +739,23 @@ static bool mlxbf_tmfifo_rxtx_one_desc(struct mlxbf_tmfifo_vring *vring,  	/* Get the descriptor of the next packet. */  	if (!vring->desc) {  		desc = mlxbf_tmfifo_get_next_pkt(vring, is_rx); -		if (!desc) -			return false; +		if (!desc) { +			/* Drop next Rx packet to avoid stuck. */ +			if (is_rx) { +				desc = &vring->drop_desc; +				vring->desc_head = desc; +				vring->desc = desc; +			} else { +				return false; +			} +		}  	} else {  		desc = vring->desc;  	}  	/* Beginning of a packet. Start to Rx/Tx packet header. */  	if (vring->pkt_len == 0) { -		mlxbf_tmfifo_rxtx_header(vring, desc, is_rx, &vring_change); +		mlxbf_tmfifo_rxtx_header(vring, &desc, is_rx, &vring_change);  		(*avail)--;  		/* Return if new packet is for another ring. */ @@ -743,17 +781,24 @@ static bool mlxbf_tmfifo_rxtx_one_desc(struct mlxbf_tmfifo_vring *vring,  		vring->rem_len -= len;  		/* Get the next desc on the chain. */ -		if (vring->rem_len > 0 && +		if (!IS_VRING_DROP(vring) && vring->rem_len > 0 &&  		    (virtio16_to_cpu(vdev, desc->flags) & VRING_DESC_F_NEXT)) {  			idx = virtio16_to_cpu(vdev, desc->next);  			desc = &vr->desc[idx];  			goto mlxbf_tmfifo_desc_done;  		} -		/* Done and release the pending packet. */ -		mlxbf_tmfifo_release_pending_pkt(vring); +		/* Done and release the packet. */  		desc = NULL;  		fifo->vring[is_rx] = NULL; +		if (!IS_VRING_DROP(vring)) { +			mlxbf_tmfifo_release_pkt(vring); +		} else { +			vring->pkt_len = 0; +			vring->desc_head = NULL; +			vring->desc = NULL; +			return false; +		}  		/*  		 * Make sure the load/store are in order before @@ -933,7 +978,7 @@ static void mlxbf_tmfifo_virtio_del_vqs(struct virtio_device *vdev)  		/* Release the pending packet. */  		if (vring->desc) -			mlxbf_tmfifo_release_pending_pkt(vring); +			mlxbf_tmfifo_release_pkt(vring);  		vq = vring->vq;  		if (vq) {  			vring->vq = NULL; @@ -1319,13 +1364,11 @@ fail:  }  /* Device remove function. */ -static int mlxbf_tmfifo_remove(struct platform_device *pdev) +static void mlxbf_tmfifo_remove(struct platform_device *pdev)  {  	struct mlxbf_tmfifo *fifo = platform_get_drvdata(pdev);  	mlxbf_tmfifo_cleanup(fifo); - -	return 0;  }  static const struct acpi_device_id mlxbf_tmfifo_acpi_match[] = { @@ -1336,7 +1379,7 @@ MODULE_DEVICE_TABLE(acpi, mlxbf_tmfifo_acpi_match);  static struct platform_driver mlxbf_tmfifo_driver = {  	.probe = mlxbf_tmfifo_probe, -	.remove = mlxbf_tmfifo_remove, +	.remove_new = mlxbf_tmfifo_remove,  	.driver = {  		.name = "bf-tmfifo",  		.acpi_match_table = mlxbf_tmfifo_acpi_match, |