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
next prev 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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.