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