lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <20140608221941.GA28334@electric-eye.fr.zoreil.com>
Date:	Mon, 9 Jun 2014 00:19:41 +0200
From:	Francois Romieu <romieu@...zoreil.com>
To:	Andy Green <andy.green@...aro.org>
Cc:	netdev@...r.kernel.org
Subject: Re: [PATCH] net-next: ethernet driver: Fujist OGMA

Andy Green <andy.green@...aro.org> :
[...]

Partial review below. The driver needs more.

> diff --git a/drivers/net/ethernet/fujitsu/ogma/ogma.h b/drivers/net/ethernet/fujitsu/ogma/ogma.h
> new file mode 100644
> index 0000000..126e458
> --- /dev/null
> +++ b/drivers/net/ethernet/fujitsu/ogma/ogma.h
[...]
> +struct ogma_priv {
> +	u32 core_enabled_flag:1;
> +	u32 gmac_rx_running_flag:1;
> +	u32 gmac_tx_running_flag:1;
> +	u32 gmac_mode_valid_flag:1;
> +	u32 normal_desc_ring_valid:1;
> +	void *base_addr;

Add __iomem annotation.

Please rename it (ioaddr, whatever). It looks like net_device.base_addr

[...]
> +static inline void ogma_write_reg(struct ogma_priv *priv, u32 reg_addr,
> +				    u32 value)
> +{
> +	writel(value, (priv->base_addr) + (reg_addr << 2));

Excess parenthesis. The driver contains quite some of those.

> +}
> +
> +static inline u32 ogma_read_reg(struct ogma_priv *priv, u32 reg_addr)
> +{
> +	return readl(priv->base_addr + (reg_addr << 2));
> +}
> +
> +static inline void pfdep_set_pkt_buf_type(void *skb, bool recv_buf_flag)
> +{
> +	struct sk_buff *skb_p = (struct sk_buff *)skb;
> +	(*((bool *) skb_p->cb)) = recv_buf_flag;

Missing empty line.

[...]
> +extern const struct net_device_ops ogma_netdev_ops;
> +extern const struct ethtool_ops ogma_ethtool_ops;
> +
> +int ogma_start_gmac(struct ogma_priv *priv, bool rx_flag, bool tx_flag);
> +int ogma_stop_gmac(struct ogma_priv *priv, bool rx_flag, bool tx_flag);
> +int ogma_set_gmac_mode(struct ogma_priv *priv,
> +		       const struct ogma_gmac_mode *mode);
> +void ogma_set_phy_reg(struct ogma_priv *priv, u8 phy_addr, u8 reg_addr,
> +		      u16 value);
> +u16 ogma_get_phy_reg(struct ogma_priv *priv, u8 phy_addr, u8 reg_addr);
> +int ogma_start_desc_ring(struct ogma_priv *priv, unsigned int id);
> +int ogma_stop_desc_ring(struct ogma_priv *priv, unsigned int id);
> +u16 ogma_get_rx_num(struct ogma_priv *priv, unsigned int id);
> +u16 ogma_get_tx_avail_num(struct ogma_priv *priv, unsigned int id);
> +int ogma_clean_tx_desc_ring(struct ogma_priv *priv, unsigned int id);
> +int ogma_clean_rx_desc_ring(struct ogma_priv *priv, unsigned int id);
> +int ogma_set_tx_pkt_data(struct ogma_priv *priv, unsigned int id,
> +	const struct ogma_tx_pkt_ctrl *tx_ctrl, u8 scat_num,
> +		const struct ogma_frag_info *scat, struct sk_buff *skb);
> +int ogma_get_rx_pkt_data(struct ogma_priv *priv, unsigned int id,
> +	struct ogma_rx_pkt_info *rx_pkt_info_p, struct ogma_frag_info *frag,
> +						u16 *len, struct sk_buff **skb);
> +int ogma_ring_irq_enable(struct ogma_priv *priv,
> +			      unsigned int id, u32 irq_factor);
> +int ogma_ring_irq_disable(struct ogma_priv *priv,
> +			       unsigned int id, u32 irq_factor);
> +int ogma_set_irq_coalesce_param(struct ogma_priv *priv, unsigned int id,
> +		u16 int_pktcnt, bool int_tmr_unit_ms_flag, u16 int_tmr_cnt);
> +
> +int ogma_alloc_desc_ring(struct ogma_priv *priv, unsigned int id);
> +void ogma_free_desc_ring(struct ogma_priv *priv, struct ogma_desc_ring *desc);
> +int ogma_setup_rx_desc_ring(struct ogma_priv *priv,
> +						struct ogma_desc_ring *desc);
> +int ogma_netdev_napi_poll(struct napi_struct *napi_p, int budget);

Excess public scope ?

> diff --git a/drivers/net/ethernet/fujitsu/ogma/ogma_desc_ring_access.c b/drivers/net/ethernet/fujitsu/ogma/ogma_desc_ring_access.c
> new file mode 100644
> index 0000000..f11a834
> --- /dev/null
> +++ b/drivers/net/ethernet/fujitsu/ogma/ogma_desc_ring_access.c
[...]
> +static void desc_lock(struct ogma_desc_ring *desc, bool *ctx)
> +{
> +	if (in_softirq()) {
> +		*ctx = 1;	/* Mark that bh is already disabled. */
> +		spin_lock(&desc->spinlock_desc);
> +	} else {
> +		*ctx = 0;
> +		spin_lock_bh(&desc->spinlock_desc);
> +	}
> +}

Device drivers should not need this kind of locking.

Let's see:
- ogma_ring_irq_enable
  Only called from the xmit handler, whence in locally disabled bh context.

- ogma_start_desc_ring
  Only called through ogma_netdev_ops.ndo_open, thus in bh enabled context.
  One may ask if open() _really_ needs this lock anyway as it can delay
  both napi processing and tx queueing.

- ogma_stop_desc_ring
  It's called in more places than ogma_start_desc_ring but it should
  work the same (disable NAPI in close, wait for quiescence, etc.).

- ogma_get_rx_num
  Called from NAPI context. No need to disable bh.

- ogma_get_tx_avail_num
  Called from NAPI context or xmit handler. No need to disable bh.
  
- ogma_clean_tx_desc_ring
  Called from NAPI, xmit or ogma_netdev_ops.ndo_open. The latter can
  control the formers. Should be a plain spinlock.

- ogma_clean_rx_desc_ring
  Only called through ogma_netdev_ops.ndo_open. See above.

- ogma_set_tx_pkt_data
  Only called from the xmit handler, whence in locally disabled bh context.

- ogma_get_rx_pkt_data
  Only called from NAPI context. No need to disable bh.

Executive summary: desc_lock should go away.

> +
> +static void desc_unlock(struct ogma_desc_ring *desc, bool *ctx)
> +{
> +	if (*ctx)
> +		spin_unlock(&desc->spinlock_desc);
> +	else
> +		spin_unlock_bh(&desc->spinlock_desc);
> +}
> +
> +static void ogma_check_desc_own_sanity(const struct ogma_desc_ring *desc,
> +					u16 idx, unsigned int expected_own)
> +{
> +	u32 tmp = *(u32 *)((void *)desc->ring_vaddr + desc->len * idx);
> +
> +	BUG_ON((tmp >> 31) != expected_own);
> +}
> +
> +int ogma_ring_irq_enable(struct ogma_priv *priv, unsigned int id,
> +								u32 irq_factor)
> +{
> +	int ret = 0;
> +	struct ogma_desc_ring *desc = &priv->desc_ring[id];
> +	bool ctx;

Please use inverted xmas tree style for variable declaration.

> +
> +	desc_lock(desc, &ctx);
> +
> +	if (!desc->running_flag) {
> +		dev_err(priv->dev, "desc ring not running\n");
> +		ret = -ENODEV;
> +		goto bail;
> +	}
> +
> +	ogma_write_reg(priv, ads_irq_set[id], irq_factor);
> +
> +bail:
> +	desc_unlock(desc, &ctx);
> +
> +	return ret;
> +}
> +
> +int ogma_ring_irq_disable(struct ogma_priv *priv,
> +			       unsigned int id, u32 irq_factor)

int ogma_ring_irq_disable(struct ogma_priv *priv, unsigned int id,
			  u32 irq_factor)

> +{
> +	ogma_write_reg(priv, desc_ring_irq_inten_clr_reg_addr[id], irq_factor);
> +
> +	return 0;

Why does it return anything ? It should be void.

> +}
> +
> +static int alloc_pkt_buf(struct device *dev, u16 len, void **addr_p,
> +				phys_addr_t *phys, struct sk_buff **pskb)
> +{
> +	struct sk_buff *skb = dev_alloc_skb(len + 2);
> +	if (!skb)
> +		return -ENOMEM;
> +
> +	/* Reserve leading 2 bytes to make IP header word-aligned. */
> +	skb_reserve(skb, 2);

netdev_alloc_skb_ip_align

> +
> +	*phys = dma_map_single(dev, skb->data, (size_t) len, DMA_FROM_DEVICE);
> +	if (!*phys) {
> +		dev_kfree_skb(skb);
> +
> +		return -ENOMEM;
> +	}
> +
> +	*addr_p = (void *)skb->data;
> +	*pskb = skb;
> +
> +	/* Mark that this is a receiving buffer. */
> +	pfdep_set_pkt_buf_type(skb, 1);

The comment underlines a poor naming.

> +
> +	return 0;
> +}
> +
> +void kfree_pkt_buf(struct device *dev, u16 len, void *addr,
> +	phys_addr_t phys_addr, bool last_flag, struct sk_buff *skb)
> +{
> +	dma_unmap_single(dev, phys_addr, (size_t) len,
> +			 (pfdep_is_recv_pkt_buf(skb) ?
> +			  DMA_FROM_DEVICE : DMA_TO_DEVICE));

Excess parenthesis.

> +
> +	if (last_flag)
> +		dev_kfree_skb(skb);
> +}
> +
> +int ogma_alloc_desc_ring(struct ogma_priv *priv, unsigned int id)
> +{
> +	int ret = 0;
> +	struct ogma_desc_ring *desc = &priv->desc_ring[id];
> +	struct ogma_desc_param *param = &priv->desc_ring[id].param;
> +	u8 rx_desc_entry_len = 0;
> +
> +	if ((priv->param.desc_param[id].valid_flag) &&
> +	    ((priv->param.desc_param[id].entry_num < OGMA_DESC_MIN) ||
> +	     (priv->param.desc_param[id].entry_num > OGMA_DESC_MAX))) {

A local variable for &priv->param.desc_param[id] would not hurt.

[...]
> +	desc->ring_vaddr = dma_alloc_coherent(NULL,
> +		desc->len * param->entry_num, &desc->deschys_addr, GFP_KERNEL);

Indent should line things up with the first character after the parenthesis.

> +	if (!desc->ring_vaddr) {
> +		ret = -ENOMEM;
> +		dev_err(priv->dev, "%s: failed to alloc\n", __func__);
> +		goto err;
> +	}
> +
> +	memset(desc->ring_vaddr, 0, (u32) desc->len * param->entry_num);
> +	desc->frag = kmalloc(sizeof(struct ogma_frag_info) * param->entry_num,
> +								GFP_NOWAIT);

Indent.

> +	if (!desc->frag) {
> +		ret = -ENOMEM;
> +		dev_err(priv->dev, "%s: failed to alloc\n", __func__);
> +		goto err;
> +	}
> +
> +	memset(desc->frag, 0, sizeof(struct ogma_frag_info) * param->entry_num);
> +	desc->priv = kmalloc(sizeof(struct sk_buff *) * param->entry_num,
> +								GFP_NOWAIT);

Indent.

> +	if (!desc->priv) {
> +		ret = -ENOMEM;
> +		dev_err(priv->dev, "%s: failed to alloc priv\n", __func__);
> +		goto err;
> +	}
> +
> +	memset(desc->priv, 0, sizeof(struct sk_buff *) * param->entry_num);
> +
> +	return 0;
> +
> +err:
> +	ogma_free_desc_ring(priv, desc);
> +
> +	return ret;
> +}
> +
> +void ogma_uninit_pkt_desc_ring(struct ogma_priv *priv,
> +			       struct ogma_desc_ring *desc)
> +{
> +	u16 idx;
> +	u32 tmp;
> +	bool last_flag;
> +	int count = desc->param.entry_num;
> +
> +	for (idx = 0; idx < count; idx++) {
> +		if (!desc->frag[idx].addr)
> +			continue;
> +
> +		tmp = *((u32 *)((void *)desc->ring_vaddr + (desc->len * idx)));
> +		last_flag = (tmp >> 8) & 1;
> +		kfree_pkt_buf(priv->dev, desc->frag[idx].len,
> +			desc->frag[idx].addr, desc->frag[idx].phys_addr,
> +			      last_flag, desc->priv[idx]);

Broken indent. The driver contains a lot of those. :o(

Please add a local variable for desc->frag[idx].

[...]
> +static void ogma_set_rx_desc_entry(struct ogma_priv *priv,
> +	struct ogma_desc_ring *desc, u16 idx, const struct ogma_frag_info *frag,
> +						     struct sk_buff *skb)
> +{
> +	struct ogma_rx_desc_entry rx_desc_entry;
> +
> +	ogma_check_desc_own_sanity(desc, idx, 0);
> +
> +	memset(&rx_desc_entry, 0, sizeof(rx_desc_entry));
> +
> +	rx_desc_entry.attr = (1 << OGMA_RX_PKT_DESC_RING_OWN_FIELD) |
> +			     (1 << OGMA_RX_PKT_DESC_RING_FS_FIELD) |
> +			     (1 << OGMA_RX_PKT_DESC_RING_LS_FIELD);
> +
> +	rx_desc_entry.data_buf_addr = frag->phys_addr;
> +	rx_desc_entry.buf_len_info = frag->len;
> +
> +	if (idx == (desc->param.entry_num - 1))
> +		rx_desc_entry.attr |= (0x1U << OGMA_RX_PKT_DESC_RING_LD_FIELD);
> +
> +	memcpy(((void *)((void *)desc->ring_vaddr + desc->len * idx + 4)),
> +		(void *)((void *)&rx_desc_entry + 4), desc->len - 4);

Scary void * fetish.

[...]
> diff --git a/drivers/net/ethernet/fujitsu/ogma/ogma_netdev.c b/drivers/net/ethernet/fujitsu/ogma/ogma_netdev.c
> new file mode 100644
> index 0000000..2f69a29
> --- /dev/null
> +++ b/drivers/net/ethernet/fujitsu/ogma/ogma_netdev.c
[...]
> +const struct net_device_ops ogma_netdev_ops = {
> +	.ndo_open = ogma_netdev_open,
> +	.ndo_stop = ogma_netdev_stop,
> +	.ndo_start_xmit = ogma_netdev_start_xmit,
> +	.ndo_set_features = ogma_netdev_set_features,
> +	.ndo_get_stats = ogma_netdev_get_stats,
> +	.ndo_change_mtu = ogma_netdev_change_mtu,
> +	.ndo_set_mac_address = ogma_netdev_set_macaddr,
> +	.ndo_validate_addr = eth_validate_addr,
> +};

Please use tabs before "=" to line things up.

> diff --git a/drivers/net/ethernet/fujitsu/ogma/ogma_platform.c b/drivers/net/ethernet/fujitsu/ogma/ogma_platform.c
> new file mode 100644
> index 0000000..176d746
> --- /dev/null
> +++ b/drivers/net/ethernet/fujitsu/ogma/ogma_platform.c
[...]
> +int ogma_configure_normal_mode(struct ogma_priv *priv,
> +			       const struct ogma_normal_mode_hwconf
> +			       *normal_mode_hwconf_p)
> +{
[...]
> +	timeout = WAIT_FW_RDY_TIMEOUT;
> +	while (timeout-- && (ogma_read_reg(priv,
> +					   desc_ads
> +					   [OGMA_RING_NRM_RX])
> +			     & (0x1UL << OGMA_REG_DESC_RING_CONFIG_CFG_UP)))

:o(

[...]
> +static int ogma_probe(struct platform_device *pdev)
> +{
[...]
> +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +	if (!res) {
> +		dev_err(&pdev->dev, "Missing base resource\n");
> +		goto bail1;
> +	}
> +
> +	priv->base_addr = ioremap_nocache(res->start,
> +						res->end - res->start + 1);
> +	if (!priv->base_addr) {
> +		dev_err(&pdev->dev, "ioremap_nocache() failed\n");
> +		err = -EINVAL;
> +		goto bail1;

bail1, bail2, bail3 and friends are not sane label names.

I haven't found any __le{8, 16, 32} nor cpu_to_xyz in the driver. I would
had expected some in the descriptors.

-- 
Ueimor
--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ