Re: [PATCH v3 10/15] net: ethernet: mtk-eth-mac: new driver
From: Arnd Bergmann
Date: Fri May 15 2020 - 09:32:52 EST
On Thu, May 14, 2020 at 10:00 AM Bartosz Golaszewski <brgl@xxxxxxxx> wrote:
> +static int mtk_mac_ring_pop_tail(struct mtk_mac_ring *ring,
> + struct mtk_mac_ring_desc_data *desc_data)
I took another look at this function because of your comment on the locking
the descriptor updates, which seemed suspicious as the device side does not
actually use the locks to access them
> +{
> + struct mtk_mac_ring_desc *desc = &ring->descs[ring->tail];
> + unsigned int status;
> +
> + /* Let the device release the descriptor. */
> + dma_rmb();
> + status = desc->status;
> + if (!(status & MTK_MAC_DESC_BIT_COWN))
> + return -1;
The dma_rmb() seems odd here, as I don't see which prior read
is being protected by this.
> + desc_data->len = status & MTK_MAC_DESC_MSK_LEN;
> + desc_data->flags = status & ~MTK_MAC_DESC_MSK_LEN;
> + desc_data->dma_addr = ring->dma_addrs[ring->tail];
> + desc_data->skb = ring->skbs[ring->tail];
> +
> + desc->data_ptr = 0;
> + desc->status = MTK_MAC_DESC_BIT_COWN;
> + if (status & MTK_MAC_DESC_BIT_EOR)
> + desc->status |= MTK_MAC_DESC_BIT_EOR;
> +
> + /* Flush writes to descriptor memory. */
> + dma_wmb();
The comment and the barrier here seem odd as well. I would have expected
a barrier after the update to the data pointer, and only a single store
but no read of the status flag instead of the read-modify-write,
something like
desc->data_ptr = 0;
dma_wmb(); /* make pointer update visible before status update */
desc->status = MTK_MAC_DESC_BIT_COWN | (status & MTK_MAC_DESC_BIT_EOR);
> + ring->tail = (ring->tail + 1) % MTK_MAC_RING_NUM_DESCS;
> + ring->count--;
I would get rid of the 'count' here, as it duplicates the information
that is already known from the difference between head and tail, and you
can't update it atomically without holding a lock around the access to
the ring. The way I'd do this is to have the head and tail pointers
in separate cache lines, and then use READ_ONCE/WRITE_ONCE
and smp barriers to access them, with each one updated on one
thread but read by the other.
Arnd