int gve_adminq_configure_rss()

in build/gve_adminq.c [1315:1388]


int gve_adminq_configure_rss(struct gve_priv *priv, struct ethtool_rxfh_param *rxfh)
{
	dma_addr_t lut_bus = 0, key_bus = 0;
	u16 key_size = 0, lut_size = 0;
	union gve_adminq_command cmd;
	__be32 *lut = NULL;
	u8 hash_alg = 0;
	u8 *key = NULL;
	int err = 0;
	u16 i;

	switch (rxfh->hfunc) {
	case ETH_RSS_HASH_NO_CHANGE:
		break;
	case ETH_RSS_HASH_TOP:
		hash_alg = ETH_RSS_HASH_TOP;
		break;
	default:
		return -EOPNOTSUPP;
	}

	if (rxfh->indir) {
		lut_size = priv->rss_lut_size;
		lut = dma_alloc_coherent(&priv->pdev->dev,
					 lut_size * sizeof(*lut),
					 &lut_bus, GFP_KERNEL);
		if (!lut)
			return -ENOMEM;

		for (i = 0; i < priv->rss_lut_size; i++)
			lut[i] = cpu_to_be32(rxfh->indir[i]);
	}

	if (rxfh->key) {
		key_size = priv->rss_key_size;
		key = dma_alloc_coherent(&priv->pdev->dev,
					 key_size, &key_bus, GFP_KERNEL);
		if (!key) {
			err = -ENOMEM;
			goto out;
		}

		memcpy(key, rxfh->key, key_size);
	}

	/* Zero-valued fields in the cmd.configure_rss instruct the device to
	 * not update those fields.
	 */
	memset(&cmd, 0, sizeof(cmd));
	cmd.opcode = cpu_to_be32(GVE_ADMINQ_CONFIGURE_RSS);
	cmd.configure_rss = (struct gve_adminq_configure_rss) {
		.hash_types = cpu_to_be16(BIT(GVE_RSS_HASH_TCPV4) |
					  BIT(GVE_RSS_HASH_UDPV4) |
					  BIT(GVE_RSS_HASH_TCPV6) |
					  BIT(GVE_RSS_HASH_UDPV6)),
		.hash_alg = hash_alg,
		.hash_key_size = cpu_to_be16(key_size),
		.hash_lut_size = cpu_to_be16(lut_size),
		.hash_key_addr = cpu_to_be64(key_bus),
		.hash_lut_addr = cpu_to_be64(lut_bus),
	};

	err = gve_adminq_execute_cmd(priv, &cmd);

out:
	if (lut)
		dma_free_coherent(&priv->pdev->dev,
				  lut_size * sizeof(*lut),
				  lut, lut_bus);
	if (key)
		dma_free_coherent(&priv->pdev->dev,
				  key_size, key, key_bus);
	return err;
}