Merge tag 'dma-mapping-6.7-2023-10-30' of git://git.infradead.org/users/hch/dma-mapping
authorLinus Torvalds <torvalds@linux-foundation.org>
Wed, 1 Nov 2023 23:15:54 +0000 (13:15 -1000)
committerLinus Torvalds <torvalds@linux-foundation.org>
Wed, 1 Nov 2023 23:15:54 +0000 (13:15 -1000)
Pull dma-mapping updates from Christoph Hellwig:

 - get rid of the fake support for coherent DMA allocation on coldfire
   with caches (Christoph Hellwig)

 - add a few Kconfig dependencies so that Kconfig catches the use of
   invalid configurations (Christoph Hellwig)

 - fix a type in dma-debug output (Chuck Lever)

 - rewrite a comment in swiotlb (Sean Christopherson)

* tag 'dma-mapping-6.7-2023-10-30' of git://git.infradead.org/users/hch/dma-mapping:
  dma-debug: Fix a typo in a debugging eye-catcher
  swiotlb: rewrite comment explaining why the source is preserved on DMA_FROM_DEVICE
  m68k: remove unused includes from dma.c
  m68k: don't provide arch_dma_alloc for nommu/coldfire
  net: fec: use dma_alloc_noncoherent for data cache enabled coldfire
  m68k: use the coherent DMA code for coldfire without data cache
  dma-direct: warn when coherent allocations aren't supported
  dma-direct: simplify the use atomic pool logic in dma_direct_alloc
  dma-direct: add a CONFIG_ARCH_HAS_DMA_ALLOC symbol
  dma-direct: add dependencies to CONFIG_DMA_GLOBAL_POOL

1  2 
arch/m68k/Kconfig
arch/parisc/Kconfig
drivers/net/ethernet/freescale/fec_main.c
kernel/dma/swiotlb.c

diff --combined arch/m68k/Kconfig
@@@ -6,22 -6,19 +6,22 @@@ config M68
        select ARCH_HAS_BINFMT_FLAT
        select ARCH_HAS_CPU_FINALIZE_INIT if MMU
        select ARCH_HAS_CURRENT_STACK_POINTER
-       select ARCH_HAS_DMA_PREP_COHERENT if HAS_DMA && MMU && !COLDFIRE
-       select ARCH_HAS_SYNC_DMA_FOR_DEVICE if HAS_DMA
+       select ARCH_HAS_DMA_PREP_COHERENT if M68K_NONCOHERENT_DMA && !COLDFIRE
+       select ARCH_HAS_SYNC_DMA_FOR_DEVICE if M68K_NONCOHERENT_DMA
        select ARCH_HAVE_NMI_SAFE_CMPXCHG if RMW_INSNS
        select ARCH_MIGHT_HAVE_PC_PARPORT if ISA
        select ARCH_NO_PREEMPT if !COLDFIRE
        select ARCH_USE_MEMTEST if MMU_MOTOROLA
        select ARCH_WANT_IPC_PARSE_VERSION
        select BINFMT_FLAT_ARGVP_ENVP_ON_STACK
-       select DMA_DIRECT_REMAP if HAS_DMA && MMU && !COLDFIRE
+       select DMA_DIRECT_REMAP if M68K_NONCOHERENT_DMA && !COLDFIRE
        select GENERIC_ATOMIC64
        select GENERIC_CPU_DEVICES
        select GENERIC_IOMAP
        select GENERIC_IRQ_SHOW
 +      select GENERIC_LIB_ASHLDI3
 +      select GENERIC_LIB_ASHRDI3
 +      select GENERIC_LIB_LSHRDI3
        select HAS_IOPORT if PCI || ISA || ATARI_ROM_ISA
        select HAVE_ARCH_SECCOMP
        select HAVE_ARCH_SECCOMP_FILTER
diff --combined arch/parisc/Kconfig
@@@ -8,6 -8,7 +8,7 @@@ config PARIS
        select HAVE_FUNCTION_GRAPH_TRACER
        select HAVE_SYSCALL_TRACEPOINTS
        select ARCH_WANT_FRAME_POINTERS
+       select ARCH_HAS_DMA_ALLOC if PA11
        select ARCH_HAS_ELF_RANDOMIZE
        select ARCH_HAS_STRICT_KERNEL_RWX
        select ARCH_HAS_STRICT_MODULE_RWX
@@@ -25,7 -26,6 +26,7 @@@
        select INIT_ALL_POSSIBLE
        select BUG
        select BUILDTIME_TABLE_SORT
 +      select HAVE_KERNEL_UNCOMPRESSED
        select HAVE_PCI
        select HAVE_PERF_EVENTS
        select HAVE_KERNEL_BZIP2
  #include <linux/clk.h>
  #include <linux/crc32.h>
  #include <linux/platform_device.h>
 +#include <linux/property.h>
  #include <linux/mdio.h>
  #include <linux/phy.h>
  #include <linux/fec.h>
  #include <linux/of.h>
 -#include <linux/of_device.h>
  #include <linux/of_mdio.h>
  #include <linux/of_net.h>
  #include <linux/regulator/consumer.h>
@@@ -186,23 -186,66 +186,23 @@@ static struct platform_device_id fec_de
                /* keep it for coldfire */
                .name = DRIVER_NAME,
                .driver_data = 0,
 -      }, {
 -              .name = "imx25-fec",
 -              .driver_data = (kernel_ulong_t)&fec_imx25_info,
 -      }, {
 -              .name = "imx27-fec",
 -              .driver_data = (kernel_ulong_t)&fec_imx27_info,
 -      }, {
 -              .name = "imx28-fec",
 -              .driver_data = (kernel_ulong_t)&fec_imx28_info,
 -      }, {
 -              .name = "imx6q-fec",
 -              .driver_data = (kernel_ulong_t)&fec_imx6q_info,
 -      }, {
 -              .name = "mvf600-fec",
 -              .driver_data = (kernel_ulong_t)&fec_mvf600_info,
 -      }, {
 -              .name = "imx6sx-fec",
 -              .driver_data = (kernel_ulong_t)&fec_imx6x_info,
 -      }, {
 -              .name = "imx6ul-fec",
 -              .driver_data = (kernel_ulong_t)&fec_imx6ul_info,
 -      }, {
 -              .name = "imx8mq-fec",
 -              .driver_data = (kernel_ulong_t)&fec_imx8mq_info,
 -      }, {
 -              .name = "imx8qm-fec",
 -              .driver_data = (kernel_ulong_t)&fec_imx8qm_info,
 -      }, {
 -              .name = "s32v234-fec",
 -              .driver_data = (kernel_ulong_t)&fec_s32v234_info,
        }, {
                /* sentinel */
        }
  };
  MODULE_DEVICE_TABLE(platform, fec_devtype);
  
 -enum imx_fec_type {
 -      IMX25_FEC = 1,  /* runs on i.mx25/50/53 */
 -      IMX27_FEC,      /* runs on i.mx27/35/51 */
 -      IMX28_FEC,
 -      IMX6Q_FEC,
 -      MVF600_FEC,
 -      IMX6SX_FEC,
 -      IMX6UL_FEC,
 -      IMX8MQ_FEC,
 -      IMX8QM_FEC,
 -      S32V234_FEC,
 -};
 -
  static const struct of_device_id fec_dt_ids[] = {
 -      { .compatible = "fsl,imx25-fec", .data = &fec_devtype[IMX25_FEC], },
 -      { .compatible = "fsl,imx27-fec", .data = &fec_devtype[IMX27_FEC], },
 -      { .compatible = "fsl,imx28-fec", .data = &fec_devtype[IMX28_FEC], },
 -      { .compatible = "fsl,imx6q-fec", .data = &fec_devtype[IMX6Q_FEC], },
 -      { .compatible = "fsl,mvf600-fec", .data = &fec_devtype[MVF600_FEC], },
 -      { .compatible = "fsl,imx6sx-fec", .data = &fec_devtype[IMX6SX_FEC], },
 -      { .compatible = "fsl,imx6ul-fec", .data = &fec_devtype[IMX6UL_FEC], },
 -      { .compatible = "fsl,imx8mq-fec", .data = &fec_devtype[IMX8MQ_FEC], },
 -      { .compatible = "fsl,imx8qm-fec", .data = &fec_devtype[IMX8QM_FEC], },
 -      { .compatible = "fsl,s32v234-fec", .data = &fec_devtype[S32V234_FEC], },
 +      { .compatible = "fsl,imx25-fec", .data = &fec_imx25_info, },
 +      { .compatible = "fsl,imx27-fec", .data = &fec_imx27_info, },
 +      { .compatible = "fsl,imx28-fec", .data = &fec_imx28_info, },
 +      { .compatible = "fsl,imx6q-fec", .data = &fec_imx6q_info, },
 +      { .compatible = "fsl,mvf600-fec", .data = &fec_mvf600_info, },
 +      { .compatible = "fsl,imx6sx-fec", .data = &fec_imx6x_info, },
 +      { .compatible = "fsl,imx6ul-fec", .data = &fec_imx6ul_info, },
 +      { .compatible = "fsl,imx8mq-fec", .data = &fec_imx8mq_info, },
 +      { .compatible = "fsl,imx8qm-fec", .data = &fec_imx8qm_info, },
 +      { .compatible = "fsl,s32v234-fec", .data = &fec_s32v234_info, },
        { /* sentinel */ }
  };
  MODULE_DEVICE_TABLE(of, fec_dt_ids);
@@@ -363,6 -406,70 +363,70 @@@ static void fec_dump(struct net_device 
        } while (bdp != txq->bd.base);
  }
  
+ /*
+  * Coldfire does not support DMA coherent allocations, and has historically used
+  * a band-aid with a manual flush in fec_enet_rx_queue.
+  */
+ #if defined(CONFIG_COLDFIRE) && !defined(CONFIG_COLDFIRE_COHERENT_DMA)
+ static void *fec_dma_alloc(struct device *dev, size_t size, dma_addr_t *handle,
+               gfp_t gfp)
+ {
+       return dma_alloc_noncoherent(dev, size, handle, DMA_BIDIRECTIONAL, gfp);
+ }
+ static void fec_dma_free(struct device *dev, size_t size, void *cpu_addr,
+               dma_addr_t handle)
+ {
+       dma_free_noncoherent(dev, size, cpu_addr, handle, DMA_BIDIRECTIONAL);
+ }
+ #else /* !CONFIG_COLDFIRE || CONFIG_COLDFIRE_COHERENT_DMA */
+ static void *fec_dma_alloc(struct device *dev, size_t size, dma_addr_t *handle,
+               gfp_t gfp)
+ {
+       return dma_alloc_coherent(dev, size, handle, gfp);
+ }
+ static void fec_dma_free(struct device *dev, size_t size, void *cpu_addr,
+               dma_addr_t handle)
+ {
+       dma_free_coherent(dev, size, cpu_addr, handle);
+ }
+ #endif /* !CONFIG_COLDFIRE || CONFIG_COLDFIRE_COHERENT_DMA */
+ struct fec_dma_devres {
+       size_t          size;
+       void            *vaddr;
+       dma_addr_t      dma_handle;
+ };
+ static void fec_dmam_release(struct device *dev, void *res)
+ {
+       struct fec_dma_devres *this = res;
+       fec_dma_free(dev, this->size, this->vaddr, this->dma_handle);
+ }
+ static void *fec_dmam_alloc(struct device *dev, size_t size, dma_addr_t *handle,
+               gfp_t gfp)
+ {
+       struct fec_dma_devres *dr;
+       void *vaddr;
+       dr = devres_alloc(fec_dmam_release, sizeof(*dr), gfp);
+       if (!dr)
+               return NULL;
+       vaddr = fec_dma_alloc(dev, size, handle, gfp);
+       if (!vaddr) {
+               devres_free(dr);
+               return NULL;
+       }
+       dr->vaddr = vaddr;
+       dr->dma_handle = *handle;
+       dr->size = size;
+       devres_add(dev, dr);
+       return vaddr;
+ }
  static inline bool is_ipv4_pkt(struct sk_buff *skb)
  {
        return skb->protocol == htons(ETH_P_IP) && ip_hdr(skb)->version == 4;
@@@ -1617,7 -1724,11 +1681,11 @@@ fec_enet_rx_queue(struct net_device *nd
        }
  #endif
  
- #ifdef CONFIG_M532x
+ #if defined(CONFIG_COLDFIRE) && !defined(CONFIG_COLDFIRE_COHERENT_DMA)
+       /*
+        * Hacky flush of all caches instead of using the DMA API for the TSO
+        * headers.
+        */
        flush_cache_all();
  #endif
        rxq = fep->rx_queue[queue_id];
@@@ -1789,7 -1900,7 +1857,7 @@@ rx_processing_done
        rxq->bd.cur = bdp;
  
        if (xdp_result & FEC_ENET_XDP_REDIR)
 -              xdp_do_flush_map();
 +              xdp_do_flush();
  
        return pkt_received;
  }
@@@ -2864,10 -2975,12 +2932,10 @@@ static void fec_enet_get_strings(struc
        switch (stringset) {
        case ETH_SS_STATS:
                for (i = 0; i < ARRAY_SIZE(fec_stats); i++) {
 -                      memcpy(data, fec_stats[i].name, ETH_GSTRING_LEN);
 -                      data += ETH_GSTRING_LEN;
 +                      ethtool_sprintf(&data, "%s", fec_stats[i].name);
                }
                for (i = 0; i < ARRAY_SIZE(fec_xdp_stat_strs); i++) {
 -                      strncpy(data, fec_xdp_stat_strs[i], ETH_GSTRING_LEN);
 -                      data += ETH_GSTRING_LEN;
 +                      ethtool_sprintf(&data, "%s", fec_xdp_stat_strs[i]);
                }
                page_pool_ethtool_stats_get_strings(data);
  
@@@ -3243,10 -3356,9 +3311,9 @@@ static void fec_enet_free_queue(struct 
        for (i = 0; i < fep->num_tx_queues; i++)
                if (fep->tx_queue[i] && fep->tx_queue[i]->tso_hdrs) {
                        txq = fep->tx_queue[i];
-                       dma_free_coherent(&fep->pdev->dev,
-                                         txq->bd.ring_size * TSO_HEADER_SIZE,
-                                         txq->tso_hdrs,
-                                         txq->tso_hdrs_dma);
+                       fec_dma_free(&fep->pdev->dev,
+                                    txq->bd.ring_size * TSO_HEADER_SIZE,
+                                    txq->tso_hdrs, txq->tso_hdrs_dma);
                }
  
        for (i = 0; i < fep->num_rx_queues; i++)
@@@ -3276,10 -3388,9 +3343,9 @@@ static int fec_enet_alloc_queue(struct 
                txq->tx_stop_threshold = FEC_MAX_SKB_DESCS;
                txq->tx_wake_threshold = FEC_MAX_SKB_DESCS + 2 * MAX_SKB_FRAGS;
  
-               txq->tso_hdrs = dma_alloc_coherent(&fep->pdev->dev,
+               txq->tso_hdrs = fec_dma_alloc(&fep->pdev->dev,
                                        txq->bd.ring_size * TSO_HEADER_SIZE,
-                                       &txq->tso_hdrs_dma,
-                                       GFP_KERNEL);
+                                       &txq->tso_hdrs_dma, GFP_KERNEL);
                if (!txq->tso_hdrs) {
                        ret = -ENOMEM;
                        goto alloc_failed;
@@@ -3998,8 -4109,8 +4064,8 @@@ static int fec_enet_init(struct net_dev
        bd_size = (fep->total_tx_ring_size + fep->total_rx_ring_size) * dsize;
  
        /* Allocate memory for buffer descriptors. */
-       cbd_base = dmam_alloc_coherent(&fep->pdev->dev, bd_size, &bd_dma,
-                                      GFP_KERNEL);
+       cbd_base = fec_dmam_alloc(&fep->pdev->dev, bd_size, &bd_dma,
+                                 GFP_KERNEL);
        if (!cbd_base) {
                ret = -ENOMEM;
                goto free_queue_mem;
@@@ -4247,13 -4358,14 +4313,13 @@@ fec_probe(struct platform_device *pdev
        phy_interface_t interface;
        struct net_device *ndev;
        int i, irq, ret = 0;
 -      const struct of_device_id *of_id;
        static int dev_id;
        struct device_node *np = pdev->dev.of_node, *phy_node;
        int num_tx_qs;
        int num_rx_qs;
        char irq_name[8];
        int irq_cnt;
 -      struct fec_devinfo *dev_info;
 +      const struct fec_devinfo *dev_info;
  
        fec_enet_get_queue_num(pdev, &num_tx_qs, &num_rx_qs);
  
        /* setup board info structure */
        fep = netdev_priv(ndev);
  
 -      of_id = of_match_device(fec_dt_ids, &pdev->dev);
 -      if (of_id)
 -              pdev->id_entry = of_id->data;
 -      dev_info = (struct fec_devinfo *)pdev->id_entry->driver_data;
 +      dev_info = device_get_match_data(&pdev->dev);
 +      if (!dev_info)
 +              dev_info = (const struct fec_devinfo *)pdev->id_entry->driver_data;
        if (dev_info)
                fep->quirks = dev_info->quirks;
  
diff --combined kernel/dma/swiotlb.c
@@@ -678,11 -678,6 +678,11 @@@ static struct io_tlb_pool *swiotlb_allo
        size_t pool_size;
        size_t tlb_size;
  
 +      if (nslabs > SLABS_PER_PAGE << MAX_ORDER) {
 +              nslabs = SLABS_PER_PAGE << MAX_ORDER;
 +              nareas = limit_nareas(nareas, nslabs);
 +      }
 +
        pool_size = sizeof(*pool) + array_size(sizeof(*pool->areas), nareas);
        pool = kzalloc(pool_size, gfp);
        if (!pool)
@@@ -1301,11 -1296,13 +1301,13 @@@ phys_addr_t swiotlb_tbl_map_single(stru
                pool->slots[index + i].orig_addr = slot_addr(orig_addr, i);
        tlb_addr = slot_addr(pool->start, index) + offset;
        /*
-        * When dir == DMA_FROM_DEVICE we could omit the copy from the orig
-        * to the tlb buffer, if we knew for sure the device will
-        * overwrite the entire current content. But we don't. Thus
-        * unconditional bounce may prevent leaking swiotlb content (i.e.
-        * kernel memory) to user-space.
+        * When the device is writing memory, i.e. dir == DMA_FROM_DEVICE, copy
+        * the original buffer to the TLB buffer before initiating DMA in order
+        * to preserve the original's data if the device does a partial write,
+        * i.e. if the device doesn't overwrite the entire buffer.  Preserving
+        * the original data, even if it's garbage, is necessary to match
+        * hardware behavior.  Use of swiotlb is supposed to be transparent,
+        * i.e. swiotlb must not corrupt memory by clobbering unwritten bytes.
         */
        swiotlb_bounce(dev, tlb_addr, mapping_size, DMA_TO_DEVICE);
        return tlb_addr;