diff mbox series

[SRU,F:linux-bluefield,v3,1/1] UBUNTU: SAUCE: platform/mellanox: Add ctrl message and MAC configuration

Message ID 0071b7702200671af2861e132609230f2f13f2b9.1620303799.git.limings@nvidia.com
State New
Headers show
Series UBUNTU: SAUCE: platform/mellanox: Add ctrl message and MAC configuration | expand

Commit Message

Liming Sun May 6, 2021, 12:26 p.m. UTC
From: Liming Sun <lsun@mellanox.com>

BugLink: https://bugs.launchpad.net/bugs/1927253

This commit adds control message support and MAC configuration
based on the control message.

Signed-off-by: Liming Sun <limings@nvidia.com>
---
 drivers/platform/mellanox/mlxbf-tmfifo.c | 170 +++++++++++++++++++++++++++----
 1 file changed, 149 insertions(+), 21 deletions(-)

Comments

Krzysztof Kozlowski May 6, 2021, 12:51 p.m. UTC | #1
On 06/05/2021 08:26, Liming Sun wrote:
> From: Liming Sun <lsun@mellanox.com>
> 
> BugLink: https://bugs.launchpad.net/bugs/1927253
> 
> This commit adds control message support and MAC configuration
> based on the control message.
> 
> Signed-off-by: Liming Sun <limings@nvidia.com>
> ---
>  drivers/platform/mellanox/mlxbf-tmfifo.c | 170 +++++++++++++++++++++++++++----
>  1 file changed, 149 insertions(+), 21 deletions(-)
> 

Acked-by: Krzysztof Kozlowski <krzysztof.kozlowski@canonical.com>

Best regards,
Krzysztof
Tim Gardner May 7, 2021, 2:45 p.m. UTC | #2
Acked-by: Tim Gardner <tim.gardner@canonical.com>

I hope you're sending this upstream. Otherwise this driver is starting 
to diverge from master in a big way.

On 5/6/21 6:26 AM, Liming Sun wrote:
> From: Liming Sun <lsun@mellanox.com>
> 
> BugLink: https://bugs.launchpad.net/bugs/1927253
> 
> This commit adds control message support and MAC configuration
> based on the control message.
> 
> Signed-off-by: Liming Sun <limings@nvidia.com>
> ---
>   drivers/platform/mellanox/mlxbf-tmfifo.c | 170 +++++++++++++++++++++++++++----
>   1 file changed, 149 insertions(+), 21 deletions(-)
> 
> diff --git a/drivers/platform/mellanox/mlxbf-tmfifo.c b/drivers/platform/mellanox/mlxbf-tmfifo.c
> index 5739a966..f8005b3 100644
> --- a/drivers/platform/mellanox/mlxbf-tmfifo.c
> +++ b/drivers/platform/mellanox/mlxbf-tmfifo.c
> @@ -150,7 +150,9 @@ struct mlxbf_tmfifo_irq_info {
>    * @timer: background timer
>    * @vring: Tx/Rx ring
>    * @spin_lock: Tx/Rx spin lock
> + * @ctrl_mac: MAC address received in control message
>    * @is_ready: ready flag
> + * @send_ctrl: flag to send control message when ready
>    */
>   struct mlxbf_tmfifo {
>   	struct mlxbf_tmfifo_vdev *vdev[MLXBF_TMFIFO_VDEV_MAX];
> @@ -165,7 +167,16 @@ struct mlxbf_tmfifo {
>   	struct timer_list timer;
>   	struct mlxbf_tmfifo_vring *vring[2];
>   	spinlock_t spin_lock[2];	/* spin lock */
> -	bool is_ready;
> +	u8 ctrl_mac[ETH_ALEN];
> +	u32 is_ready : 1;
> +	u32 send_ctrl : 1;
> +};
> +
> +/* Internal message types defined in reverse order starting from 0xFF. */
> +enum {
> +	MLXBF_TMFIFO_MSG_CTRL_REQ = 0xFD,
> +	MLXBF_TMFIFO_MSG_MAC_1 = 0xFE,
> +	MLXBF_TMFIFO_MSG_MAC_2 = 0xFF
>   };
>   
>   /**
> @@ -175,11 +186,17 @@ struct mlxbf_tmfifo {
>    *       will be read by the other side as data stream in the same byte order.
>    *       The length needs to be encoded into network order so both sides
>    *       could understand it.
> + * @mac: first or second half of the MAC address depending on the type.
> + * @checksum: checksum of the message header (only control message for now).
>    */
>   struct mlxbf_tmfifo_msg_hdr {
>   	u8 type;
>   	__be16 len;
> -	u8 unused[5];
> +	union {
> +		u8 mac[3];
> +		u8 unused[4];
> +	} __packed;
> +	u8 checksum;
>   } __packed __aligned(sizeof(u64));
>   
>   /*
> @@ -491,6 +508,127 @@ static int mlxbf_tmfifo_get_tx_avail(struct mlxbf_tmfifo *fifo, int vdev_id)
>   	return fifo->tx_fifo_size - tx_reserve - count;
>   }
>   
> +/* Read the configured network MAC address from efi variable. */
> +static void mlxbf_tmfifo_get_cfg_mac(u8 *mac)
> +{
> +	efi_guid_t guid = EFI_GLOBAL_VARIABLE_GUID;
> +	unsigned long size = ETH_ALEN;
> +	u8 buf[ETH_ALEN];
> +	efi_status_t rc;
> +
> +	rc = efi.get_variable(mlxbf_tmfifo_efi_name, &guid, NULL, &size, buf);
> +	if (rc == EFI_SUCCESS && size == ETH_ALEN)
> +		ether_addr_copy(mac, buf);
> +	else
> +		ether_addr_copy(mac, mlxbf_tmfifo_net_default_mac);
> +}
> +
> +/* Set the configured network MAC address into efi variable. */
> +static efi_status_t mlxbf_tmfifo_set_cfg_mac(u8 *mac)
> +{
> +	efi_guid_t guid = EFI_GLOBAL_VARIABLE_GUID;
> +	efi_status_t status = EFI_SUCCESS;
> +	u8 old_mac[ETH_ALEN] = {0};
> +
> +	mlxbf_tmfifo_get_cfg_mac(old_mac);
> +
> +	if (memcmp(old_mac, mac, ETH_ALEN)) {
> +		status = efi.set_variable(mlxbf_tmfifo_efi_name, &guid,
> +					  EFI_VARIABLE_NON_VOLATILE |
> +					  EFI_VARIABLE_BOOTSERVICE_ACCESS |
> +					  EFI_VARIABLE_RUNTIME_ACCESS,
> +					  ETH_ALEN, mac);
> +	}
> +
> +	return status;
> +}
> +
> +/* Just adds up all the bytes of the header. */
> +static u8 mlxbf_tmfifo_ctrl_checksum(struct mlxbf_tmfifo_msg_hdr *hdr)
> +{
> +	u8 checksum = 0;
> +	int i;
> +
> +	for (i = 0; i < sizeof(*hdr); i++)
> +		checksum += ((u8 *)hdr)[i];
> +
> +	return checksum;
> +}
> +
> +static void mlxbf_tmfifo_ctrl_update_checksum(struct mlxbf_tmfifo_msg_hdr *hdr)
> +{
> +	u8 checksum;
> +
> +	hdr->checksum = 0;
> +	checksum = mlxbf_tmfifo_ctrl_checksum(hdr);
> +	hdr->checksum = ~checksum + 1;
> +}
> +
> +static bool mlxbf_tmfifo_ctrl_verify_checksum(struct mlxbf_tmfifo_msg_hdr *hdr)
> +{
> +	u8 checksum = mlxbf_tmfifo_ctrl_checksum(hdr);
> +
> +	return checksum ? false : true;
> +}
> +
> +static void mlxbf_tmfifo_ctrl_rx(struct mlxbf_tmfifo *fifo,
> +				 struct mlxbf_tmfifo_msg_hdr *hdr)
> +{
> +	if (!mlxbf_tmfifo_ctrl_verify_checksum(hdr))
> +		return;
> +
> +	switch (hdr->type) {
> +	case MLXBF_TMFIFO_MSG_CTRL_REQ:
> +		/*
> +		 * Set a flag to send the MAC address later. It can't be sent
> +		 * here since another packet might be still in the middle of
> +		 * transmission.
> +		 */
> +		fifo->send_ctrl = 1;
> +		test_and_set_bit(MLXBF_TM_TX_LWM_IRQ, &fifo->pend_events);
> +		schedule_work(&fifo->work);
> +		break;
> +	case MLXBF_TMFIFO_MSG_MAC_1:
> +		/* Get the first half of the MAC address. */
> +		memcpy(fifo->ctrl_mac, hdr->mac, sizeof(hdr->mac));
> +		break;
> +	case MLXBF_TMFIFO_MSG_MAC_2:
> +		/* Get the second half of the MAC address and update. */
> +		memcpy(fifo->ctrl_mac + sizeof(hdr->mac), hdr->mac,
> +		       sizeof(hdr->mac));
> +		mlxbf_tmfifo_set_cfg_mac(fifo->ctrl_mac);
> +		break;
> +	default:
> +		break;
> +	}
> +}
> +
> +static void mlxbf_tmfifo_ctrl_tx(struct mlxbf_tmfifo *fifo, int *num_avail)
> +{
> +	struct mlxbf_tmfifo_msg_hdr hdr;
> +	u8 mac[ETH_ALEN] = { 0 };
> +
> +	/* Send the MAC address with two control messages. */
> +	if (fifo->send_ctrl && *num_avail >= 2) {
> +		mlxbf_tmfifo_get_cfg_mac(mac);
> +
> +		hdr.type = MLXBF_TMFIFO_MSG_MAC_1;
> +		hdr.len = 0;
> +		memcpy(hdr.mac, mac, sizeof(hdr.mac));
> +		mlxbf_tmfifo_ctrl_update_checksum(&hdr);
> +		writeq(*(u64 *)&hdr, fifo->tx_base + MLXBF_TMFIFO_TX_DATA);
> +		(*num_avail)--;
> +
> +		hdr.type = MLXBF_TMFIFO_MSG_MAC_2;
> +		memcpy(hdr.mac, mac + sizeof(hdr.mac), sizeof(hdr.mac));
> +		mlxbf_tmfifo_ctrl_update_checksum(&hdr);
> +		writeq(*(u64 *)&hdr, fifo->tx_base + MLXBF_TMFIFO_TX_DATA);
> +		(*num_avail)--;
> +
> +		fifo->send_ctrl = 0;
> +	}
> +}
> +
>   /* Console Tx (move data from the output buffer into the TmFifo). */
>   static void mlxbf_tmfifo_console_tx(struct mlxbf_tmfifo *fifo, int avail)
>   {
> @@ -616,9 +754,11 @@ static void mlxbf_tmfifo_rxtx_header(struct mlxbf_tmfifo_vring *vring,
>   		/* Drain one word from the FIFO. */
>   		*(u64 *)&hdr = readq(fifo->rx_base + MLXBF_TMFIFO_RX_DATA);
>   
> -		/* Skip the length 0 packets (keepalive). */
> -		if (hdr.len == 0)
> +		/* Handle the length 0 packets (control msg). */
> +		if (hdr.len == 0) {
> +			mlxbf_tmfifo_ctrl_rx(fifo, &hdr);
>   			return;
> +		}
>   
>   		/* Check packet type. */
>   		if (hdr.type == VIRTIO_ID_NET) {
> @@ -777,6 +917,9 @@ static void mlxbf_tmfifo_rxtx(struct mlxbf_tmfifo_vring *vring, bool is_rx)
>   
>   		/* Console output always comes from the Tx buffer. */
>   		if (!is_rx && devid == VIRTIO_ID_CONSOLE) {
> +			/* Check if there is any control data to send. */
> +			mlxbf_tmfifo_ctrl_tx(fifo, &avail);
> +
>   			mlxbf_tmfifo_console_tx(fifo, avail);
>   			break;
>   		}
> @@ -1122,21 +1265,6 @@ static int mlxbf_tmfifo_delete_vdev(struct mlxbf_tmfifo *fifo, int vdev_id)
>   	return 0;
>   }
>   
> -/* Read the configured network MAC address from efi variable. */
> -static void mlxbf_tmfifo_get_cfg_mac(u8 *mac)
> -{
> -	efi_guid_t guid = EFI_GLOBAL_VARIABLE_GUID;
> -	unsigned long size = ETH_ALEN;
> -	u8 buf[ETH_ALEN];
> -	efi_status_t rc;
> -
> -	rc = efi.get_variable(mlxbf_tmfifo_efi_name, &guid, NULL, &size, buf);
> -	if (rc == EFI_SUCCESS && size == ETH_ALEN)
> -		ether_addr_copy(mac, buf);
> -	else
> -		ether_addr_copy(mac, mlxbf_tmfifo_net_default_mac);
> -}
> -
>   /* Set TmFifo thresolds which is used to trigger interrupts. */
>   static void mlxbf_tmfifo_set_threshold(struct mlxbf_tmfifo *fifo)
>   {
> @@ -1169,7 +1297,7 @@ static void mlxbf_tmfifo_cleanup(struct mlxbf_tmfifo *fifo)
>   {
>   	int i;
>   
> -	fifo->is_ready = false;
> +	fifo->is_ready = 0;
>   	del_timer_sync(&fifo->timer);
>   	mlxbf_tmfifo_disable_irqs(fifo);
>   	cancel_work_sync(&fifo->work);
> @@ -1242,7 +1370,7 @@ static int mlxbf_tmfifo_probe(struct platform_device *pdev)
>   
>   	mod_timer(&fifo->timer, jiffies + MLXBF_TMFIFO_TIMER_INTERVAL);
>   
> -	fifo->is_ready = true;
> +	fifo->is_ready = 1;
>   	return 0;
>   
>   fail:
>
Liming Sun May 7, 2021, 2:47 p.m. UTC | #3
Thanks! We'll work on the upstreaming of these changes as well.

- Liming

> -----Original Message-----
> From: Tim Gardner <tim.gardner@canonical.com>
> Sent: Friday, May 7, 2021 10:46 AM
> To: Liming Sun <limings@nvidia.com>; kernel-team@lists.ubuntu.com
> Cc: Liming Sun <limings@nvidia.com>
> Subject: ACK: [SRU][F:linux-bluefield][PATCH v3 1/1] UBUNTU: SAUCE:
> platform/mellanox: Add ctrl message and MAC configuration
> 
> Acked-by: Tim Gardner <tim.gardner@canonical.com>
> 
> I hope you're sending this upstream. Otherwise this driver is starting
> to diverge from master in a big way.
> 
> On 5/6/21 6:26 AM, Liming Sun wrote:
> > From: Liming Sun <lsun@mellanox.com>
> >
> > BugLink:
> https://nam11.safelinks.protection.outlook.com/?url=https%3A%2F%2Fbugs
> .launchpad.net%2Fbugs%2F1927253&amp;data=04%7C01%7Climings%40nvid
> ia.com%7C0d8b253582f5494c1f5b08d91166d74d%7C43083d15727340c1b7db3
> 9efd9ccc17a%7C0%7C0%7C637559955667992655%7CUnknown%7CTWFpbGZs
> b3d8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn
> 0%3D%7C1000&amp;sdata=2DScwx9btdWQrtGLTbvYyCMAzhba%2Bw9FkKgK
> 4muz7vo%3D&amp;reserved=0
> >
> > This commit adds control message support and MAC configuration
> > based on the control message.
> >
> > Signed-off-by: Liming Sun <limings@nvidia.com>
> > ---
> >   drivers/platform/mellanox/mlxbf-tmfifo.c | 170
> +++++++++++++++++++++++++++----
> >   1 file changed, 149 insertions(+), 21 deletions(-)
> >
> > diff --git a/drivers/platform/mellanox/mlxbf-tmfifo.c
> b/drivers/platform/mellanox/mlxbf-tmfifo.c
> > index 5739a966..f8005b3 100644
> > --- a/drivers/platform/mellanox/mlxbf-tmfifo.c
> > +++ b/drivers/platform/mellanox/mlxbf-tmfifo.c
> > @@ -150,7 +150,9 @@ struct mlxbf_tmfifo_irq_info {
> >    * @timer: background timer
> >    * @vring: Tx/Rx ring
> >    * @spin_lock: Tx/Rx spin lock
> > + * @ctrl_mac: MAC address received in control message
> >    * @is_ready: ready flag
> > + * @send_ctrl: flag to send control message when ready
> >    */
> >   struct mlxbf_tmfifo {
> >   	struct mlxbf_tmfifo_vdev *vdev[MLXBF_TMFIFO_VDEV_MAX];
> > @@ -165,7 +167,16 @@ struct mlxbf_tmfifo {
> >   	struct timer_list timer;
> >   	struct mlxbf_tmfifo_vring *vring[2];
> >   	spinlock_t spin_lock[2];	/* spin lock */
> > -	bool is_ready;
> > +	u8 ctrl_mac[ETH_ALEN];
> > +	u32 is_ready : 1;
> > +	u32 send_ctrl : 1;
> > +};
> > +
> > +/* Internal message types defined in reverse order starting from 0xFF. */
> > +enum {
> > +	MLXBF_TMFIFO_MSG_CTRL_REQ = 0xFD,
> > +	MLXBF_TMFIFO_MSG_MAC_1 = 0xFE,
> > +	MLXBF_TMFIFO_MSG_MAC_2 = 0xFF
> >   };
> >
> >   /**
> > @@ -175,11 +186,17 @@ struct mlxbf_tmfifo {
> >    *       will be read by the other side as data stream in the same byte order.
> >    *       The length needs to be encoded into network order so both sides
> >    *       could understand it.
> > + * @mac: first or second half of the MAC address depending on the type.
> > + * @checksum: checksum of the message header (only control message
> for now).
> >    */
> >   struct mlxbf_tmfifo_msg_hdr {
> >   	u8 type;
> >   	__be16 len;
> > -	u8 unused[5];
> > +	union {
> > +		u8 mac[3];
> > +		u8 unused[4];
> > +	} __packed;
> > +	u8 checksum;
> >   } __packed __aligned(sizeof(u64));
> >
> >   /*
> > @@ -491,6 +508,127 @@ static int mlxbf_tmfifo_get_tx_avail(struct
> mlxbf_tmfifo *fifo, int vdev_id)
> >   	return fifo->tx_fifo_size - tx_reserve - count;
> >   }
> >
> > +/* Read the configured network MAC address from efi variable. */
> > +static void mlxbf_tmfifo_get_cfg_mac(u8 *mac)
> > +{
> > +	efi_guid_t guid = EFI_GLOBAL_VARIABLE_GUID;
> > +	unsigned long size = ETH_ALEN;
> > +	u8 buf[ETH_ALEN];
> > +	efi_status_t rc;
> > +
> > +	rc = efi.get_variable(mlxbf_tmfifo_efi_name, &guid, NULL, &size,
> buf);
> > +	if (rc == EFI_SUCCESS && size == ETH_ALEN)
> > +		ether_addr_copy(mac, buf);
> > +	else
> > +		ether_addr_copy(mac, mlxbf_tmfifo_net_default_mac);
> > +}
> > +
> > +/* Set the configured network MAC address into efi variable. */
> > +static efi_status_t mlxbf_tmfifo_set_cfg_mac(u8 *mac)
> > +{
> > +	efi_guid_t guid = EFI_GLOBAL_VARIABLE_GUID;
> > +	efi_status_t status = EFI_SUCCESS;
> > +	u8 old_mac[ETH_ALEN] = {0};
> > +
> > +	mlxbf_tmfifo_get_cfg_mac(old_mac);
> > +
> > +	if (memcmp(old_mac, mac, ETH_ALEN)) {
> > +		status = efi.set_variable(mlxbf_tmfifo_efi_name, &guid,
> > +					  EFI_VARIABLE_NON_VOLATILE |
> > +
> EFI_VARIABLE_BOOTSERVICE_ACCESS |
> > +					  EFI_VARIABLE_RUNTIME_ACCESS,
> > +					  ETH_ALEN, mac);
> > +	}
> > +
> > +	return status;
> > +}
> > +
> > +/* Just adds up all the bytes of the header. */
> > +static u8 mlxbf_tmfifo_ctrl_checksum(struct mlxbf_tmfifo_msg_hdr
> *hdr)
> > +{
> > +	u8 checksum = 0;
> > +	int i;
> > +
> > +	for (i = 0; i < sizeof(*hdr); i++)
> > +		checksum += ((u8 *)hdr)[i];
> > +
> > +	return checksum;
> > +}
> > +
> > +static void mlxbf_tmfifo_ctrl_update_checksum(struct
> mlxbf_tmfifo_msg_hdr *hdr)
> > +{
> > +	u8 checksum;
> > +
> > +	hdr->checksum = 0;
> > +	checksum = mlxbf_tmfifo_ctrl_checksum(hdr);
> > +	hdr->checksum = ~checksum + 1;
> > +}
> > +
> > +static bool mlxbf_tmfifo_ctrl_verify_checksum(struct
> mlxbf_tmfifo_msg_hdr *hdr)
> > +{
> > +	u8 checksum = mlxbf_tmfifo_ctrl_checksum(hdr);
> > +
> > +	return checksum ? false : true;
> > +}
> > +
> > +static void mlxbf_tmfifo_ctrl_rx(struct mlxbf_tmfifo *fifo,
> > +				 struct mlxbf_tmfifo_msg_hdr *hdr)
> > +{
> > +	if (!mlxbf_tmfifo_ctrl_verify_checksum(hdr))
> > +		return;
> > +
> > +	switch (hdr->type) {
> > +	case MLXBF_TMFIFO_MSG_CTRL_REQ:
> > +		/*
> > +		 * Set a flag to send the MAC address later. It can't be sent
> > +		 * here since another packet might be still in the middle of
> > +		 * transmission.
> > +		 */
> > +		fifo->send_ctrl = 1;
> > +		test_and_set_bit(MLXBF_TM_TX_LWM_IRQ, &fifo-
> >pend_events);
> > +		schedule_work(&fifo->work);
> > +		break;
> > +	case MLXBF_TMFIFO_MSG_MAC_1:
> > +		/* Get the first half of the MAC address. */
> > +		memcpy(fifo->ctrl_mac, hdr->mac, sizeof(hdr->mac));
> > +		break;
> > +	case MLXBF_TMFIFO_MSG_MAC_2:
> > +		/* Get the second half of the MAC address and update. */
> > +		memcpy(fifo->ctrl_mac + sizeof(hdr->mac), hdr->mac,
> > +		       sizeof(hdr->mac));
> > +		mlxbf_tmfifo_set_cfg_mac(fifo->ctrl_mac);
> > +		break;
> > +	default:
> > +		break;
> > +	}
> > +}
> > +
> > +static void mlxbf_tmfifo_ctrl_tx(struct mlxbf_tmfifo *fifo, int *num_avail)
> > +{
> > +	struct mlxbf_tmfifo_msg_hdr hdr;
> > +	u8 mac[ETH_ALEN] = { 0 };
> > +
> > +	/* Send the MAC address with two control messages. */
> > +	if (fifo->send_ctrl && *num_avail >= 2) {
> > +		mlxbf_tmfifo_get_cfg_mac(mac);
> > +
> > +		hdr.type = MLXBF_TMFIFO_MSG_MAC_1;
> > +		hdr.len = 0;
> > +		memcpy(hdr.mac, mac, sizeof(hdr.mac));
> > +		mlxbf_tmfifo_ctrl_update_checksum(&hdr);
> > +		writeq(*(u64 *)&hdr, fifo->tx_base +
> MLXBF_TMFIFO_TX_DATA);
> > +		(*num_avail)--;
> > +
> > +		hdr.type = MLXBF_TMFIFO_MSG_MAC_2;
> > +		memcpy(hdr.mac, mac + sizeof(hdr.mac), sizeof(hdr.mac));
> > +		mlxbf_tmfifo_ctrl_update_checksum(&hdr);
> > +		writeq(*(u64 *)&hdr, fifo->tx_base +
> MLXBF_TMFIFO_TX_DATA);
> > +		(*num_avail)--;
> > +
> > +		fifo->send_ctrl = 0;
> > +	}
> > +}
> > +
> >   /* Console Tx (move data from the output buffer into the TmFifo). */
> >   static void mlxbf_tmfifo_console_tx(struct mlxbf_tmfifo *fifo, int avail)
> >   {
> > @@ -616,9 +754,11 @@ static void mlxbf_tmfifo_rxtx_header(struct
> mlxbf_tmfifo_vring *vring,
> >   		/* Drain one word from the FIFO. */
> >   		*(u64 *)&hdr = readq(fifo->rx_base +
> MLXBF_TMFIFO_RX_DATA);
> >
> > -		/* Skip the length 0 packets (keepalive). */
> > -		if (hdr.len == 0)
> > +		/* Handle the length 0 packets (control msg). */
> > +		if (hdr.len == 0) {
> > +			mlxbf_tmfifo_ctrl_rx(fifo, &hdr);
> >   			return;
> > +		}
> >
> >   		/* Check packet type. */
> >   		if (hdr.type == VIRTIO_ID_NET) {
> > @@ -777,6 +917,9 @@ static void mlxbf_tmfifo_rxtx(struct
> mlxbf_tmfifo_vring *vring, bool is_rx)
> >
> >   		/* Console output always comes from the Tx buffer. */
> >   		if (!is_rx && devid == VIRTIO_ID_CONSOLE) {
> > +			/* Check if there is any control data to send. */
> > +			mlxbf_tmfifo_ctrl_tx(fifo, &avail);
> > +
> >   			mlxbf_tmfifo_console_tx(fifo, avail);
> >   			break;
> >   		}
> > @@ -1122,21 +1265,6 @@ static int mlxbf_tmfifo_delete_vdev(struct
> mlxbf_tmfifo *fifo, int vdev_id)
> >   	return 0;
> >   }
> >
> > -/* Read the configured network MAC address from efi variable. */
> > -static void mlxbf_tmfifo_get_cfg_mac(u8 *mac)
> > -{
> > -	efi_guid_t guid = EFI_GLOBAL_VARIABLE_GUID;
> > -	unsigned long size = ETH_ALEN;
> > -	u8 buf[ETH_ALEN];
> > -	efi_status_t rc;
> > -
> > -	rc = efi.get_variable(mlxbf_tmfifo_efi_name, &guid, NULL, &size,
> buf);
> > -	if (rc == EFI_SUCCESS && size == ETH_ALEN)
> > -		ether_addr_copy(mac, buf);
> > -	else
> > -		ether_addr_copy(mac, mlxbf_tmfifo_net_default_mac);
> > -}
> > -
> >   /* Set TmFifo thresolds which is used to trigger interrupts. */
> >   static void mlxbf_tmfifo_set_threshold(struct mlxbf_tmfifo *fifo)
> >   {
> > @@ -1169,7 +1297,7 @@ static void mlxbf_tmfifo_cleanup(struct
> mlxbf_tmfifo *fifo)
> >   {
> >   	int i;
> >
> > -	fifo->is_ready = false;
> > +	fifo->is_ready = 0;
> >   	del_timer_sync(&fifo->timer);
> >   	mlxbf_tmfifo_disable_irqs(fifo);
> >   	cancel_work_sync(&fifo->work);
> > @@ -1242,7 +1370,7 @@ static int mlxbf_tmfifo_probe(struct
> platform_device *pdev)
> >
> >   	mod_timer(&fifo->timer, jiffies +
> MLXBF_TMFIFO_TIMER_INTERVAL);
> >
> > -	fifo->is_ready = true;
> > +	fifo->is_ready = 1;
> >   	return 0;
> >
> >   fail:
> >
> 
> --
> -----------
> Tim Gardner
> Canonical, Inc
diff mbox series

Patch

diff --git a/drivers/platform/mellanox/mlxbf-tmfifo.c b/drivers/platform/mellanox/mlxbf-tmfifo.c
index 5739a966..f8005b3 100644
--- a/drivers/platform/mellanox/mlxbf-tmfifo.c
+++ b/drivers/platform/mellanox/mlxbf-tmfifo.c
@@ -150,7 +150,9 @@  struct mlxbf_tmfifo_irq_info {
  * @timer: background timer
  * @vring: Tx/Rx ring
  * @spin_lock: Tx/Rx spin lock
+ * @ctrl_mac: MAC address received in control message
  * @is_ready: ready flag
+ * @send_ctrl: flag to send control message when ready
  */
 struct mlxbf_tmfifo {
 	struct mlxbf_tmfifo_vdev *vdev[MLXBF_TMFIFO_VDEV_MAX];
@@ -165,7 +167,16 @@  struct mlxbf_tmfifo {
 	struct timer_list timer;
 	struct mlxbf_tmfifo_vring *vring[2];
 	spinlock_t spin_lock[2];	/* spin lock */
-	bool is_ready;
+	u8 ctrl_mac[ETH_ALEN];
+	u32 is_ready : 1;
+	u32 send_ctrl : 1;
+};
+
+/* Internal message types defined in reverse order starting from 0xFF. */
+enum {
+	MLXBF_TMFIFO_MSG_CTRL_REQ = 0xFD,
+	MLXBF_TMFIFO_MSG_MAC_1 = 0xFE,
+	MLXBF_TMFIFO_MSG_MAC_2 = 0xFF
 };
 
 /**
@@ -175,11 +186,17 @@  struct mlxbf_tmfifo {
  *       will be read by the other side as data stream in the same byte order.
  *       The length needs to be encoded into network order so both sides
  *       could understand it.
+ * @mac: first or second half of the MAC address depending on the type.
+ * @checksum: checksum of the message header (only control message for now).
  */
 struct mlxbf_tmfifo_msg_hdr {
 	u8 type;
 	__be16 len;
-	u8 unused[5];
+	union {
+		u8 mac[3];
+		u8 unused[4];
+	} __packed;
+	u8 checksum;
 } __packed __aligned(sizeof(u64));
 
 /*
@@ -491,6 +508,127 @@  static int mlxbf_tmfifo_get_tx_avail(struct mlxbf_tmfifo *fifo, int vdev_id)
 	return fifo->tx_fifo_size - tx_reserve - count;
 }
 
+/* Read the configured network MAC address from efi variable. */
+static void mlxbf_tmfifo_get_cfg_mac(u8 *mac)
+{
+	efi_guid_t guid = EFI_GLOBAL_VARIABLE_GUID;
+	unsigned long size = ETH_ALEN;
+	u8 buf[ETH_ALEN];
+	efi_status_t rc;
+
+	rc = efi.get_variable(mlxbf_tmfifo_efi_name, &guid, NULL, &size, buf);
+	if (rc == EFI_SUCCESS && size == ETH_ALEN)
+		ether_addr_copy(mac, buf);
+	else
+		ether_addr_copy(mac, mlxbf_tmfifo_net_default_mac);
+}
+
+/* Set the configured network MAC address into efi variable. */
+static efi_status_t mlxbf_tmfifo_set_cfg_mac(u8 *mac)
+{
+	efi_guid_t guid = EFI_GLOBAL_VARIABLE_GUID;
+	efi_status_t status = EFI_SUCCESS;
+	u8 old_mac[ETH_ALEN] = {0};
+
+	mlxbf_tmfifo_get_cfg_mac(old_mac);
+
+	if (memcmp(old_mac, mac, ETH_ALEN)) {
+		status = efi.set_variable(mlxbf_tmfifo_efi_name, &guid,
+					  EFI_VARIABLE_NON_VOLATILE |
+					  EFI_VARIABLE_BOOTSERVICE_ACCESS |
+					  EFI_VARIABLE_RUNTIME_ACCESS,
+					  ETH_ALEN, mac);
+	}
+
+	return status;
+}
+
+/* Just adds up all the bytes of the header. */
+static u8 mlxbf_tmfifo_ctrl_checksum(struct mlxbf_tmfifo_msg_hdr *hdr)
+{
+	u8 checksum = 0;
+	int i;
+
+	for (i = 0; i < sizeof(*hdr); i++)
+		checksum += ((u8 *)hdr)[i];
+
+	return checksum;
+}
+
+static void mlxbf_tmfifo_ctrl_update_checksum(struct mlxbf_tmfifo_msg_hdr *hdr)
+{
+	u8 checksum;
+
+	hdr->checksum = 0;
+	checksum = mlxbf_tmfifo_ctrl_checksum(hdr);
+	hdr->checksum = ~checksum + 1;
+}
+
+static bool mlxbf_tmfifo_ctrl_verify_checksum(struct mlxbf_tmfifo_msg_hdr *hdr)
+{
+	u8 checksum = mlxbf_tmfifo_ctrl_checksum(hdr);
+
+	return checksum ? false : true;
+}
+
+static void mlxbf_tmfifo_ctrl_rx(struct mlxbf_tmfifo *fifo,
+				 struct mlxbf_tmfifo_msg_hdr *hdr)
+{
+	if (!mlxbf_tmfifo_ctrl_verify_checksum(hdr))
+		return;
+
+	switch (hdr->type) {
+	case MLXBF_TMFIFO_MSG_CTRL_REQ:
+		/*
+		 * Set a flag to send the MAC address later. It can't be sent
+		 * here since another packet might be still in the middle of
+		 * transmission.
+		 */
+		fifo->send_ctrl = 1;
+		test_and_set_bit(MLXBF_TM_TX_LWM_IRQ, &fifo->pend_events);
+		schedule_work(&fifo->work);
+		break;
+	case MLXBF_TMFIFO_MSG_MAC_1:
+		/* Get the first half of the MAC address. */
+		memcpy(fifo->ctrl_mac, hdr->mac, sizeof(hdr->mac));
+		break;
+	case MLXBF_TMFIFO_MSG_MAC_2:
+		/* Get the second half of the MAC address and update. */
+		memcpy(fifo->ctrl_mac + sizeof(hdr->mac), hdr->mac,
+		       sizeof(hdr->mac));
+		mlxbf_tmfifo_set_cfg_mac(fifo->ctrl_mac);
+		break;
+	default:
+		break;
+	}
+}
+
+static void mlxbf_tmfifo_ctrl_tx(struct mlxbf_tmfifo *fifo, int *num_avail)
+{
+	struct mlxbf_tmfifo_msg_hdr hdr;
+	u8 mac[ETH_ALEN] = { 0 };
+
+	/* Send the MAC address with two control messages. */
+	if (fifo->send_ctrl && *num_avail >= 2) {
+		mlxbf_tmfifo_get_cfg_mac(mac);
+
+		hdr.type = MLXBF_TMFIFO_MSG_MAC_1;
+		hdr.len = 0;
+		memcpy(hdr.mac, mac, sizeof(hdr.mac));
+		mlxbf_tmfifo_ctrl_update_checksum(&hdr);
+		writeq(*(u64 *)&hdr, fifo->tx_base + MLXBF_TMFIFO_TX_DATA);
+		(*num_avail)--;
+
+		hdr.type = MLXBF_TMFIFO_MSG_MAC_2;
+		memcpy(hdr.mac, mac + sizeof(hdr.mac), sizeof(hdr.mac));
+		mlxbf_tmfifo_ctrl_update_checksum(&hdr);
+		writeq(*(u64 *)&hdr, fifo->tx_base + MLXBF_TMFIFO_TX_DATA);
+		(*num_avail)--;
+
+		fifo->send_ctrl = 0;
+	}
+}
+
 /* Console Tx (move data from the output buffer into the TmFifo). */
 static void mlxbf_tmfifo_console_tx(struct mlxbf_tmfifo *fifo, int avail)
 {
@@ -616,9 +754,11 @@  static void mlxbf_tmfifo_rxtx_header(struct mlxbf_tmfifo_vring *vring,
 		/* Drain one word from the FIFO. */
 		*(u64 *)&hdr = readq(fifo->rx_base + MLXBF_TMFIFO_RX_DATA);
 
-		/* Skip the length 0 packets (keepalive). */
-		if (hdr.len == 0)
+		/* Handle the length 0 packets (control msg). */
+		if (hdr.len == 0) {
+			mlxbf_tmfifo_ctrl_rx(fifo, &hdr);
 			return;
+		}
 
 		/* Check packet type. */
 		if (hdr.type == VIRTIO_ID_NET) {
@@ -777,6 +917,9 @@  static void mlxbf_tmfifo_rxtx(struct mlxbf_tmfifo_vring *vring, bool is_rx)
 
 		/* Console output always comes from the Tx buffer. */
 		if (!is_rx && devid == VIRTIO_ID_CONSOLE) {
+			/* Check if there is any control data to send. */
+			mlxbf_tmfifo_ctrl_tx(fifo, &avail);
+
 			mlxbf_tmfifo_console_tx(fifo, avail);
 			break;
 		}
@@ -1122,21 +1265,6 @@  static int mlxbf_tmfifo_delete_vdev(struct mlxbf_tmfifo *fifo, int vdev_id)
 	return 0;
 }
 
-/* Read the configured network MAC address from efi variable. */
-static void mlxbf_tmfifo_get_cfg_mac(u8 *mac)
-{
-	efi_guid_t guid = EFI_GLOBAL_VARIABLE_GUID;
-	unsigned long size = ETH_ALEN;
-	u8 buf[ETH_ALEN];
-	efi_status_t rc;
-
-	rc = efi.get_variable(mlxbf_tmfifo_efi_name, &guid, NULL, &size, buf);
-	if (rc == EFI_SUCCESS && size == ETH_ALEN)
-		ether_addr_copy(mac, buf);
-	else
-		ether_addr_copy(mac, mlxbf_tmfifo_net_default_mac);
-}
-
 /* Set TmFifo thresolds which is used to trigger interrupts. */
 static void mlxbf_tmfifo_set_threshold(struct mlxbf_tmfifo *fifo)
 {
@@ -1169,7 +1297,7 @@  static void mlxbf_tmfifo_cleanup(struct mlxbf_tmfifo *fifo)
 {
 	int i;
 
-	fifo->is_ready = false;
+	fifo->is_ready = 0;
 	del_timer_sync(&fifo->timer);
 	mlxbf_tmfifo_disable_irqs(fifo);
 	cancel_work_sync(&fifo->work);
@@ -1242,7 +1370,7 @@  static int mlxbf_tmfifo_probe(struct platform_device *pdev)
 
 	mod_timer(&fifo->timer, jiffies + MLXBF_TMFIFO_TIMER_INTERVAL);
 
-	fifo->is_ready = true;
+	fifo->is_ready = 1;
 	return 0;
 
 fail: