devicetree.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Lino Sanfilippo <LinoSanfilippo@gmx.de>
To: Timur Tabi <timur@codeaurora.org>,
	netdev@vger.kernel.org, devicetree@vger.kernel.org,
	linux-arm-msm@vger.kernel.org, sdharia@codeaurora.org,
	shankerd@codeaurora.org, vikrams@codeaurora.org,
	cov@codeaurora.org, gavidov@codeaurora.org, robh+dt@kernel.org,
	andrew@lunn.ch, bjorn.andersson@linaro.org, mlangsdo@redhat.com,
	jcm@redhat.com, agross@codeaurora.org, davem@davemloft.net,
	f.fainelli@gmail.com
Subject: Re: [PATCH] [v6] net: emac: emac gigabit ethernet controller driver
Date: Mon, 4 Jul 2016 01:04:12 +0200	[thread overview]
Message-ID: <577999EC.1010104@gmx.de> (raw)
In-Reply-To: <1466812008-26686-1-git-send-email-timur@codeaurora.org>

Hi,

some remarks below.

> +/* Fill up receive queue's RFD with preallocated receive buffers */
> +static void emac_mac_rx_descs_refill(struct emac_adapter *adpt,
> +				    struct emac_rx_queue *rx_q)
> +{
> +	struct emac_buffer *curr_rxbuf;
> +	struct emac_buffer *next_rxbuf;
> +	unsigned int count = 0;
> +	u32 next_produce_idx;
> +
> +	next_produce_idx = rx_q->rfd.produce_idx + 1;
> +	if (next_produce_idx == rx_q->rfd.count)
> +		next_produce_idx = 0;
> +
> +	curr_rxbuf = GET_RFD_BUFFER(rx_q, rx_q->rfd.produce_idx);
> +	next_rxbuf = GET_RFD_BUFFER(rx_q, next_produce_idx);
> +
> +	/* this always has a blank rx_buffer*/
> +	while (!next_rxbuf->dma_addr) {
> +		struct sk_buff *skb;
> +		void *skb_data;
> +
> +		skb = dev_alloc_skb(adpt->rxbuf_size + NET_IP_ALIGN);
> +		if (!skb)
> +			break;
> +
> +		/* Make buffer alignment 2 beyond a 16 byte boundary
> +		 * this will result in a 16 byte aligned IP header after
> +		 * the 14 byte MAC header is removed
> +		 */
> +		skb_reserve(skb, NET_IP_ALIGN);

__netdev_alloc_skb_ip_align will do this for you.


> +		skb_data = skb->data;
> +		curr_rxbuf->skb = skb;
> +		curr_rxbuf->length = adpt->rxbuf_size;
> +		curr_rxbuf->dma_addr = dma_map_single(adpt->netdev->dev.parent,
> +						      skb_data,
> +						      curr_rxbuf->length,
> +						      DMA_FROM_DEVICE);


Mapping can fail. You should check the result via dma_mapping_error(). 
There are several other places in which dma_map_single() is called and the return value 
is not checked.

> +/* Bringup the interface/HW */
> +int emac_mac_up(struct emac_adapter *adpt)
> +{
> +	struct net_device *netdev = adpt->netdev;
> +	struct emac_irq	*irq = &adpt->irq;
> +	int ret;
> +
> +	emac_mac_rx_tx_ring_reset_all(adpt);
> +	emac_mac_config(adpt);
> +
> +	ret = request_irq(irq->irq, emac_isr, 0, EMAC_MAC_IRQ_RES, irq);
> +	if (ret) {
> +		netdev_err(adpt->netdev,
> +			   "error:%d on request_irq(%d:%s flags:0)\n", ret,
> +			   irq->irq, EMAC_MAC_IRQ_RES);
> +		return ret;
> +	}
> +
> +	emac_mac_rx_descs_refill(adpt, &adpt->rx_q);
> +
> +	ret = phy_connect_direct(netdev, adpt->phydev, emac_adjust_link,
> +				 PHY_INTERFACE_MODE_SGMII);
> +	if (ret) {
> +		netdev_err(adpt->netdev,
> +			   "error:%d on request_irq(%d:%s flags:0)\n", ret,
> +			   irq->irq, EMAC_MAC_IRQ_RES);

freeing the irq is missing


> +
> +/* Bring down the interface/HW */
> +void emac_mac_down(struct emac_adapter *adpt, bool reset)
> +{
> +	struct net_device *netdev = adpt->netdev;
> +	unsigned long flags;
> +
> +	netif_stop_queue(netdev);
> +	napi_disable(&adpt->rx_q.napi);
> +
> +	phy_disconnect(adpt->phydev);
> +
> +	/* disable mac irq */
> +	writel(DIS_INT, adpt->base + EMAC_INT_STATUS);
> +	writel(0, adpt->base + EMAC_INT_MASK);
> +	synchronize_irq(adpt->irq.irq);
> +	free_irq(adpt->irq.irq, &adpt->irq);
> +	clear_bit(EMAC_STATUS_TASK_REINIT_REQ, &adpt->status);
> +
> +	cancel_work_sync(&adpt->tx_ts_task);
> +	spin_lock_irqsave(&adpt->tx_ts_lock, flags);

Maybe I am missing something but AFAICS tx_ts_lock is never called from irq context, so 
there is no reason to disable irqs. 

> +
> +/* Push the received skb to upper layers */
> +static void emac_receive_skb(struct emac_rx_queue *rx_q,
> +			     struct sk_buff *skb,
> +			     u16 vlan_tag, bool vlan_flag)
> +{
> +	if (vlan_flag) {
> +		u16 vlan;
> +
> +		EMAC_TAG_TO_VLAN(vlan_tag, vlan);
> +		__vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), vlan);
> +	}
> +
> +	napi_gro_receive(&rx_q->napi, skb);

napi_gro_receive requires rx checksum offload. However emac_receive_skb() is also called if
hardware checksumming is disabled. 

> +
> +/* Transmit the packet using specified transmit queue */
> +int emac_mac_tx_buf_send(struct emac_adapter *adpt, struct emac_tx_queue *tx_q,
> +			 struct sk_buff *skb)
> +{
> +	struct emac_tpd tpd;
> +	u32 prod_idx;
> +
> +	if (!emac_tx_has_enough_descs(tx_q, skb)) {

Drivers should avoid this situation right from the start by checking after each transmission if the max number
 of possible descriptors is still available for a further transmission and stop the queue if there are not.
Furthermore there does not seem to be any function that wakes the queue up again once it has been stopped.

> +
> +/* reinitialize */
> +void emac_reinit_locked(struct emac_adapter *adpt)
> +{
> +	while (test_and_set_bit(EMAC_STATUS_RESETTING, &adpt->status))
> +		msleep(20); /* Reset might take few 10s of ms */
> +
> +	emac_mac_down(adpt, true);
> +
> +	emac_sgmii_reset(adpt);
> +	emac_mac_up(adpt);

emac_mac_up() may fail, so this case should be handled properly.

> +/* Change the Maximum Transfer Unit (MTU) */
> +static int emac_change_mtu(struct net_device *netdev, int new_mtu)
> +{
> +	unsigned int max_frame = new_mtu + ETH_HLEN + ETH_FCS_LEN + VLAN_HLEN;
> +	struct emac_adapter *adpt = netdev_priv(netdev);
> +	unsigned int old_mtu = netdev->mtu;
> +
> +	if ((max_frame < EMAC_MIN_ETH_FRAME_SIZE) ||
> +	    (max_frame > EMAC_MAX_ETH_FRAME_SIZE)) {
> +		netdev_err(adpt->netdev, "error: invalid MTU setting\n");
> +		return -EINVAL;
> +	}
> +
> +	if ((old_mtu != new_mtu) && netif_running(netdev)) {

Setting the new mtu in case that the interface is down is missing.
Also the first check is not needed, since this function is only called if
there is a change of the mtu. 


> +/* Provide network statistics info for the interface */
> +static struct rtnl_link_stats64 *emac_get_stats64(struct net_device *netdev,
> +						  struct rtnl_link_stats64 *net_stats)
> +{
> +	struct emac_adapter *adpt = netdev_priv(netdev);
> +	unsigned int addr = REG_MAC_RX_STATUS_BIN;
> +	struct emac_stats *stats = &adpt->stats;
> +	u64 *stats_itr = &adpt->stats.rx_ok;
> +	u32 val;
> +
> +	mutex_lock(&stats->lock);

It is not allowed to sleep in this function, so you have to use something else for locking,
e.g. a spinlock.

> +static int emac_probe(struct platform_device *pdev)
> +{
> +	struct net_device *netdev;
> +	struct emac_adapter *adpt;
> +	struct emac_phy *phy;
> +	u16 devid, revid;
> +	u32 reg;
> +	int ret;
> +
> +	/* The EMAC itself is capable of 64-bit DMA. If the SOC limits that
> +	 * range, then we expect platform code to adjust the mask accordingly.
> +	 */
> +	ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64));
> +	if (ret) {
> +		dev_err(&pdev->dev, "could not set DMA mask\n");
> +		return ret;
> +	}
> +
> +	netdev = alloc_etherdev(sizeof(struct emac_adapter));
> +	if (!netdev)
> +		return -ENOMEM;
> +
> +	dev_set_drvdata(&pdev->dev, netdev);
> +	SET_NETDEV_DEV(netdev, &pdev->dev);
> +
> +	adpt = netdev_priv(netdev);
> +	adpt->netdev = netdev;
> +	phy = &adpt->phy;
> +	adpt->msg_enable = EMAC_MSG_DEFAULT;
> +
> +	mutex_init(&adpt->stats.lock);
> +
> +	adpt->irq.mask = RX_PKT_INT0 | IMR_NORMAL_MASK;
> +
> +	ret = emac_probe_resources(pdev, adpt);
> +	if (ret)
> +		goto err_undo_netdev;
> +
> +	/* initialize clocks */
> +	ret = emac_clks_phase1_init(pdev, adpt);
> +	if (ret)
> +		goto err_undo_resources;
> +
> +	netdev->watchdog_timeo = EMAC_WATCHDOG_TIME;
> +	netdev->irq = adpt->irq.irq;
> +
> +	if (adpt->timestamp_en)
> +		adpt->rrd_size = EMAC_TS_RRD_SIZE;
> +	else
> +		adpt->rrd_size = EMAC_RRD_SIZE;
> +
> +	adpt->tpd_size = EMAC_TPD_SIZE;
> +	adpt->rfd_size = EMAC_RFD_SIZE;
> +
> +	/* init netdev */
> +	netdev->netdev_ops = &emac_netdev_ops;
> +
> +	/* init adapter */
> +	emac_init_adapter(adpt);
> +
> +	/* init phy */
> +	ret = emac_phy_config(pdev, adpt);
> +	if (ret)
> +		goto err_undo_clk_phase1;
> +
> +	/* enable clocks */
> +	ret = emac_clks_phase2_init(pdev, adpt);
> +	if (ret)
> +		goto err_undo_clk_phase2;
> +
> +	/* reset mac */
> +	emac_mac_reset(adpt);
> +
> +	/* set hw features */
> +	netdev->features = NETIF_F_SG | NETIF_F_HW_CSUM | NETIF_F_RXCSUM |
> +			NETIF_F_TSO | NETIF_F_TSO6 | NETIF_F_HW_VLAN_CTAG_RX |
> +			NETIF_F_HW_VLAN_CTAG_TX;
> +	netdev->hw_features = netdev->features;
> +
> +	netdev->vlan_features |= NETIF_F_SG | NETIF_F_HW_CSUM |
> +				 NETIF_F_TSO | NETIF_F_TSO6;
> +
> +	INIT_WORK(&adpt->work_thread, emac_work_thread);
> +
> +	/* Initialize queues */
> +	emac_mac_rx_tx_ring_init_all(pdev, adpt);
> +
> +	netif_napi_add(netdev, &adpt->rx_q.napi, emac_napi_rtx, 64);
> +
> +	spin_lock_init(&adpt->tx_ts_lock);
> +	skb_queue_head_init(&adpt->tx_ts_pending_queue);
> +	skb_queue_head_init(&adpt->tx_ts_ready_queue);
> +	INIT_WORK(&adpt->tx_ts_task, emac_mac_tx_ts_periodic_routine);
> +
> +	strlcpy(netdev->name, "eth%d", sizeof(netdev->name));

This is already done by alloc_etherdev.


Regards,
Lino

  parent reply	other threads:[~2016-07-03 23:04 UTC|newest]

Thread overview: 22+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2016-06-24 23:46 [PATCH] [v6] net: emac: emac gigabit ethernet controller driver Timur Tabi
2016-06-28 20:56 ` Rob Herring
2016-06-29  7:55 ` David Miller
2016-06-29  8:17 ` Arnd Bergmann
2016-06-29 12:17   ` Timur Tabi
2016-06-29 14:07     ` Arnd Bergmann
2016-06-29 14:33       ` Timur Tabi
2016-06-29 15:04         ` Arnd Bergmann
2016-06-29 15:10           ` Timur Tabi
2016-06-29 15:34             ` Arnd Bergmann
2016-06-29 15:46               ` Timur Tabi
2016-06-29 19:45                 ` Arnd Bergmann
2016-06-29 20:16                   ` Timur Tabi
2016-07-01 13:54                     ` Arnd Bergmann
2016-08-03 21:24                       ` Timur Tabi
2016-08-04  9:21                         ` Arnd Bergmann
2016-08-04 14:24                           ` Timur Tabi
2016-07-03 23:04 ` Lino Sanfilippo [this message]
2016-07-28 19:12   ` Timur Tabi
2016-07-30 10:26     ` Lino Sanfilippo
2016-08-02 17:59       ` Timur Tabi
2016-08-03 20:00         ` Timur Tabi

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=577999EC.1010104@gmx.de \
    --to=linosanfilippo@gmx.de \
    --cc=agross@codeaurora.org \
    --cc=andrew@lunn.ch \
    --cc=bjorn.andersson@linaro.org \
    --cc=cov@codeaurora.org \
    --cc=davem@davemloft.net \
    --cc=devicetree@vger.kernel.org \
    --cc=f.fainelli@gmail.com \
    --cc=gavidov@codeaurora.org \
    --cc=jcm@redhat.com \
    --cc=linux-arm-msm@vger.kernel.org \
    --cc=mlangsdo@redhat.com \
    --cc=netdev@vger.kernel.org \
    --cc=robh+dt@kernel.org \
    --cc=sdharia@codeaurora.org \
    --cc=shankerd@codeaurora.org \
    --cc=timur@codeaurora.org \
    --cc=vikrams@codeaurora.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).