Thread (72 messages) 72 messages, 7 authors, 2011-03-03

Re: [PATCH v4] net: add Faraday FTMAC100 10/100 Ethernet driver

flat view

From: Michał Mirosław <hidden>
Date: 2011-01-21 12:26:29
Also in: lkml

2011/1/21 Po-Yu Chuang [off-list ref]:
From: Po-Yu Chuang <redacted>

FTMAC100 Ethernet Media Access Controller supports 10/100 Mbps and
MII.  This driver has been working on some ARM/NDS32 SoC's including
Faraday A320 and Andes AG101.

Signed-off-by: Po-Yu Chuang <redacted>
[...]
quoted hunk ↗ jump to hunk
+static void ftmac100_txdes_reset(struct ftmac100_txdes *txdes)
+{
+       /* clear all except end of ring bit */
+       txdes->txdes0 = 0;
+       txdes->txdes1 &= FTMAC100_TXDES1_EDOTR;
+       txdes->txdes2 = 0;
+       txdes->txdes3 = 0;
+}
This also probably needs cpu_to_le32().

[...]
quoted hunk ↗ jump to hunk
+static void ftmac100_free_buffers(struct ftmac100 *priv)
+{
+       int i;
+
+       for (i = 0; i < RX_QUEUE_ENTRIES; i += 2) {
+               struct ftmac100_rxdes *rxdes = &priv->descs->rxdes[i];
+               dma_addr_t d = ftmac100_rxdes_get_dma_addr(rxdes);
+               void *page = ftmac100_rxdes_get_va(rxdes);
+
+               if (d)
+                       dma_unmap_single(priv->dev, d, PAGE_SIZE,
+                                        DMA_FROM_DEVICE);
+
+               if (page != NULL)
+                       free_page((unsigned long)page);
+       }
+
[...]
quoted hunk ↗ jump to hunk
+static int ftmac100_alloc_buffers(struct ftmac100 *priv)
+{
+       int i;
+
+       priv->descs = dma_alloc_coherent(priv->dev,
+                                        sizeof(struct ftmac100_descs),
+                                        &priv->descs_dma_addr,
+                                        GFP_KERNEL | GFP_DMA);
+       if (priv->descs == NULL)
+               return -ENOMEM;
+
+       memset(priv->descs, 0, sizeof(struct ftmac100_descs));
+
+       /* initialize RX ring */
+
+       ftmac100_rxdes_set_end_of_ring(&priv->descs->rxdes[RX_QUEUE_ENTRIES - 1]);
+
+       for (i = 0; i < RX_QUEUE_ENTRIES; i += 2) {
+               struct ftmac100_rxdes *rxdes = &priv->descs->rxdes[i];
+               void *page;
+               dma_addr_t d;
+
+               page = (void *)__get_free_page(GFP_KERNEL | GFP_DMA);
+               if (page == NULL)
+                       goto err;
+
+               d = dma_map_single(priv->dev, page, PAGE_SIZE, DMA_FROM_DEVICE);
+               if (unlikely(dma_mapping_error(priv->dev, d))) {
+                       free_page((unsigned long)page);
+                       goto err;
+               }
+
+               /*
+                * The hardware enforces a sub-2K maximum packet size, so we
+                * put two buffers on every hardware page.
+                */
+               ftmac100_rxdes_set_va(rxdes, page);
+               ftmac100_rxdes_set_va(rxdes + 1, page + PAGE_SIZE / 2);
+
+               ftmac100_rxdes_set_dma_addr(rxdes, d);
+               ftmac100_rxdes_set_dma_addr(rxdes + 1, d + PAGE_SIZE / 2);
+
+               ftmac100_rxdes_set_buffer_size(rxdes, RX_BUF_SIZE);
+               ftmac100_rxdes_set_buffer_size(rxdes + 1, RX_BUF_SIZE);
+
+               ftmac100_rxdes_set_dma_own(rxdes);
+               ftmac100_rxdes_set_dma_own(rxdes + 1);
+       }
[...]

Did you test this? This looks like it will result in double free after
packet RX, as you are giving the same page (referenced once) to two
distinct RX descriptors, that may be assigned different packets.

Since your not implementing any RX offloads, you might just allocate
fresh skb's with alloc_skb() and store skb pointer in rxdes3. Since
hardware doesn't touch it, you can skip cpu_to_le32()/le32_to_cpu()
there (leave a comment, though).

Unless this needs to work for ISA devices, you should drop GFP_DMA
allocation flag.

Best Regards,
Michał Mirosław
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help