[RFC PATCH 05/29] net/qdma: add device init and uninit functions

Stephen Hemminger stephen at networkplumber.org
Wed Jul 6 17:35:09 CEST 2022


On Wed,  6 Jul 2022 13:21:55 +0530
Aman Kumar <aman.kumar at vvdntech.in> wrote:

> +/* parse a sysfs file containing one integer value */
> +static int parse_sysfs_value(const char *filename, uint32_t *val)
> +{
> +	FILE *f;
> +	char buf[BUFSIZ];
> +	char *end = NULL;
> +
> +	f = fopen(filename, "r");
> +	if (f == NULL) {
> +		PMD_DRV_LOG(ERR, "%s(): Failed to open sysfs file %s\n",
> +				__func__, filename);
> +		return -1;
> +	}
> +
> +	if (fgets(buf, sizeof(buf), f) == NULL) {
> +		PMD_DRV_LOG(ERR, "%s(): Failed to read sysfs value %s\n",
> +			__func__, filename);
> +		fclose(f);
> +		return -1;
> +	}
> +	*val = (uint32_t)strtoul(buf, &end, 0);
> +	if ((buf[0] == '\0') || end == NULL || (*end != '\n')) {
> +		PMD_DRV_LOG(ERR, "%s(): Failed to parse sysfs value %s\n",
> +				__func__, filename);
> +		fclose(f);
> +		return -1;
> +	}
> +	fclose(f);
> +	return 0;
> +}

Why reinvent eal_parse_sysfs_value?

> +/* Split up a pci address into its constituent parts. */
> +static int parse_pci_addr_format(const char *buf,
> +		int bufsize, struct rte_pci_addr *addr)
> +{
> +	/* first split on ':' */
> +	union splitaddr {
> +		struct {
> +			char *domain;
> +			char *bus;
> +			char *devid;
> +			char *function;
> +		};
> +		/* last element-separator is "." not ":" */
> +		char *str[PCI_FMT_NVAL];
> +	} splitaddr;
> +
> +	char *buf_copy = strndup(buf, bufsize);
> +	if (buf_copy == NULL) {
> +		PMD_DRV_LOG(ERR, "Failed to get pci address duplicate copy\n");
> +		return -1;
> +	}
> +
> +	if (rte_strsplit(buf_copy, bufsize, splitaddr.str, PCI_FMT_NVAL, ':')
> +			!= PCI_FMT_NVAL - 1) {
> +		PMD_DRV_LOG(ERR, "Failed to split pci address string\n");
> +		goto error;
> +	}
> +
> +	/* final split is on '.' between devid and function */
> +	splitaddr.function = strchr(splitaddr.devid, '.');
> +	if (splitaddr.function == NULL) {
> +		PMD_DRV_LOG(ERR, "Failed to split pci devid and function\n");
> +		goto error;
> +	}
> +	*splitaddr.function++ = '\0';
> +
> +	/* now convert to int values */
> +	addr->domain = strtoul(splitaddr.domain, NULL, 16);
> +	addr->bus = strtoul(splitaddr.bus, NULL, 16);
> +	addr->devid = strtoul(splitaddr.devid, NULL, 16);
> +	addr->function = strtoul(splitaddr.function, NULL, 10);
> +
> +	free(buf_copy); /* free the copy made with strdup */
> +	return 0;
> +
> +error:
> +	free(buf_copy);
> +	return -1;
> +}

Looks like you didn't see rte_pci_addr_parse..

> +/* Get max pci bus number from the corresponding pci bridge device */
> +static int get_max_pci_bus_num(uint8_t start_bus, uint8_t *end_bus)
> +{
> +	char dirname[PATH_MAX];
> +	char filename[PATH_MAX];
> +	char cfgname[PATH_MAX];
> +	struct rte_pci_addr addr;
> +	struct dirent *dp;
> +	uint32_t pci_class_code;
> +	uint8_t sec_bus_num, sub_bus_num;
> +	DIR *dir;
> +	int ret, fd;
> +
> +	/* Initialize end bus number to zero */
> +	*end_bus = 0;
> +
> +	/* Open pci devices directory */
> +	dir = opendir(rte_pci_get_sysfs_path());
> +	if (dir == NULL) {
> +		PMD_DRV_LOG(ERR, "%s(): opendir failed\n",
> +			__func__);
> +		return -1;
> +	}
> +
> +	while ((dp = readdir(dir)) != NULL) {
> +		if (dp->d_name[0] == '.')
> +			continue;
> +
> +		/* Split pci address to get bus, devid and function numbers */
> +		if (parse_pci_addr_format(dp->d_name,
> +				sizeof(dp->d_name), &addr) != 0)
> +			continue;
> +
> +		snprintf(dirname, sizeof(dirname), "%s/%s",
> +				rte_pci_get_sysfs_path(), dp->d_name);
> +
> +		/* get class code */
> +		snprintf(filename, sizeof(filename), "%s/class", dirname);
> +		if (parse_sysfs_value(filename, &pci_class_code) < 0) {
> +			PMD_DRV_LOG(ERR, "Failed to get pci class code\n");
> +			goto error;
> +		}
> +
> +		/* Get max pci number from pci bridge device */
> +		if ((((pci_class_code >> PCI_CONFIG_CLASS_CODE_SHIFT) & 0xFF) ==
> +				PCI_CONFIG_BRIDGE_DEVICE)) {
> +			snprintf(cfgname, sizeof(cfgname),
> +					"%s/config", dirname);
> +			fd = open(cfgname, O_RDWR);
> +			if (fd < 0) {
> +				PMD_DRV_LOG(ERR, "Failed to open %s\n",
> +					cfgname);
> +				goto error;
> +			}
> +
> +			/* get secondary bus number */
> +			ret = pread(fd, &sec_bus_num, sizeof(uint8_t),
> +						PCI_SECONDARY_BUS);
> +			if (ret == -1) {
> +				PMD_DRV_LOG(ERR, "Failed to read secondary bus number\n");
> +				close(fd);
> +				goto error;
> +			}
> +
> +			/* get subordinate bus number */
> +			ret = pread(fd, &sub_bus_num, sizeof(uint8_t),
> +						PCI_SUBORDINATE_BUS);
> +			if (ret == -1) {
> +				PMD_DRV_LOG(ERR, "Failed to read subordinate bus number\n");
> +				close(fd);
> +				goto error;
> +			}
> +
> +			/* Get max bus number by checking if given bus number
> +			 * falls in between secondary and subordinate bus
> +			 * numbers of this pci bridge device.
> +			 */
> +			if (start_bus >= sec_bus_num &&
> +			    start_bus <= sub_bus_num) {
> +				*end_bus = sub_bus_num;
> +				close(fd);
> +				closedir(dir);
> +				return 0;
> +			}
> +
> +			close(fd);
> +		}
> +	}
> +
> +error:
> +	closedir(dir);
> +	return -1;
> +}
> +
>  /**
>   * DPDK callback to register a PCI device.
>   *
> @@ -39,7 +232,12 @@ static struct rte_pci_id qdma_pci_id_tbl[] = {
>   */
>  static int qdma_eth_dev_init(struct rte_eth_dev *dev)
>  {
> +	struct qdma_pci_dev *dma_priv;
> +	uint8_t *baseaddr;
> +	int i, idx, ret;
>  	struct rte_pci_device *pci_dev;
> +	uint16_t num_vfs;
> +	uint8_t max_pci_bus = 0;
>  
>  	/* sanity checks */
>  	if (dev == NULL)
> @@ -59,6 +257,88 @@ static int qdma_eth_dev_init(struct rte_eth_dev *dev)
>  	if (rte_eal_process_type() != RTE_PROC_PRIMARY)
>  		return 0;
>  
> +	/* allocate space for a single Ethernet MAC address */
> +	dev->data->mac_addrs = rte_zmalloc("qdma", RTE_ETHER_ADDR_LEN * 1, 0);
> +	if (dev->data->mac_addrs == NULL)
> +		return -ENOMEM;
> +
> +	/* Copy some dummy Ethernet MAC address for QDMA device
> +	 * This will change in real NIC device...
> +	 * TODO: Read MAC from EEPROM
> +	 */
> +	for (i = 0; i < RTE_ETHER_ADDR_LEN; ++i)
> +		dev->data->mac_addrs[0].addr_bytes[i] = 0x15 + i;

If you don't have a real EEPROM to read, use rte_eth_random_addr() instead.

> +
> +	/* Init system & device */
> +	dma_priv = (struct qdma_pci_dev *)dev->data->dev_private;
> +	dma_priv->is_vf = 0;
> +	dma_priv->is_master = 0;
> +	dma_priv->vf_online_count = 0;
> +	dma_priv->timer_count = DEFAULT_TIMER_CNT_TRIG_MODE_TIMER;
> +
> +	dma_priv->en_desc_prefetch = 0; /* Keep prefetch default to 0 */
> +	dma_priv->cmpt_desc_len = 0;
> +	dma_priv->c2h_bypass_mode = 0;
> +	dma_priv->h2c_bypass_mode = 0;
> +
> +	dma_priv->config_bar_idx = DEFAULT_PF_CONFIG_BAR;
> +	dma_priv->bypass_bar_idx = BAR_ID_INVALID;
> +	dma_priv->user_bar_idx = BAR_ID_INVALID;
> +
> +	/* Check and handle device devargs */
> +	if (qdma_check_kvargs(dev->device->devargs, dma_priv)) {
> +		PMD_DRV_LOG(INFO, "devargs failed\n");
> +		rte_free(dev->data->mac_addrs);
> +		return -EINVAL;
> +	}
> +
> +	/* Store BAR address and length of Config BAR */
> +	baseaddr = (uint8_t *)
> +			pci_dev->mem_resource[dma_priv->config_bar_idx].addr;
> +	dma_priv->bar_addr[dma_priv->config_bar_idx] = baseaddr;
> +
> +	idx = qdma_identify_bars(dev);
> +	if (idx < 0) {
> +		rte_free(dev->data->mac_addrs);
> +		return -EINVAL;
> +	}
> +
> +	/* Store BAR address and length of AXI Master Lite BAR(user bar) */
> +	if (dma_priv->user_bar_idx >= 0) {
> +		baseaddr = (uint8_t *)
> +			    pci_dev->mem_resource[dma_priv->user_bar_idx].addr;
> +		dma_priv->bar_addr[dma_priv->user_bar_idx] = baseaddr;
> +	}
> +
> +	PMD_DRV_LOG(INFO, "QDMA device driver probe:");
> +
> +	ret = get_max_pci_bus_num(pci_dev->addr.bus, &max_pci_bus);
> +	if (ret != 0 && !max_pci_bus) {
> +		PMD_DRV_LOG(ERR, "Failed to get max pci bus number\n");
> +		rte_free(dev->data->mac_addrs);
> +		return -EINVAL;
> +	}
> +	PMD_DRV_LOG(INFO, "PCI max bus number : 0x%x", max_pci_bus);
> +
> +	if (!dma_priv->reset_in_progress) {
> +		num_vfs = pci_dev->max_vfs;
> +		if (num_vfs) {
> +			dma_priv->vfinfo = rte_zmalloc("vfinfo",
> +				sizeof(struct qdma_vf_info) * num_vfs, 0);
> +			if (dma_priv->vfinfo == NULL) {
> +				PMD_DRV_LOG(ERR, "Cannot allocate memory for private VF info\n");
> +				return -ENOMEM;
> +			}
> +
> +			/* Mark all VFs with invalid function id mapping*/
> +			for (i = 0; i < num_vfs; i++)
> +				dma_priv->vfinfo[i].func_id =
> +					QDMA_FUNC_ID_INVALID;
> +		}
> +	}
> +
> +	dma_priv->reset_in_progress = 0;
> +
>  	return 0;
>  }


More information about the dev mailing list