dma: return NULL on dma_alloc_coherent failure
Subsystems (15)
PATCH 1/1 dma: return NULL on dma_alloc_coherent failure
The majority of our calls to dma_alloc_coherent check for a NULL return that would indicate an error as that's the Linux API as well.
In barebox, dma_alloc_coherent panics though. This mostly doesn't matter, because these are mostly fixed size allocations at driver probe time, but we have some older code like the Freescale UDC driver that allocates coherent memory out of a poller context.
This can turn a simple out-of-memory condition when writing too many bytes over fastboot into a panic.
Make the failure mode graceful by propagating -ENOMEM instead.
--- arch/arm/cpu/mmu-common.c | 4 +++- arch/arm/include/asm/dma.h | 4 +++- arch/mips/include/asm/dma.h | 5 ++++- arch/riscv/cpu/dma.c | 4 +++- arch/sandbox/include/asm/dma.h | 4 +++- arch/x86/include/asm/dma.h | 5 +++-- drivers/crypto/caam/caamrng.c | 2 ++ drivers/crypto/caam/pbl-init.c | 7 +++++-- drivers/dma/ti/k3-udma-am62l.c | 4 ++++ drivers/dma/ti/k3-udma.c | 4 ++++ drivers/firmware/qemu_fw_cfg.c | 4 ++++ drivers/net/ag71xx.c | 6 +++++- drivers/net/arc_emac.c | 3 +++ drivers/net/at91_ether.c | 5 +++++ drivers/net/e1000/main.c | 2 ++ drivers/net/fec_imx.c | 5 +++++ drivers/net/gianfar.c | 8 +++++++- drivers/net/macb.c | 9 ++++++++- drivers/net/mvneta.c | 11 +++++++++-- drivers/net/orion-gbe.c | 4 ++++ drivers/net/r8169_main.c | 17 +++++++++++++++-- drivers/net/rtl8139.c | 3 +++ drivers/soc/starfive/jh7100_dma.c | 4 +++- drivers/usb/host/ehci-hcd.c | 10 ++++++++++ drivers/video/atmel_lcdfb_core.c | 7 ++++++- drivers/video/pxa.c | 5 +++++ drivers/video/ramfb.c | 2 ++ 27 files changed, 130 insertions(+), 18 deletions(-)
arch/arm/cpu/mmu-common.c +3 -1
@@ -43,7 +43,9 @@ void *dma_alloc_map(struct device *dev,void *ret; size =PAGE_ALIGN (size); - ret =xmemalign (PAGE_SIZE , size); + ret =memalign (PAGE_SIZE , size); +if (!ret) +return NULL ;if (dma_handle) *dma_handle = (dma_addr_t )ret;
arch/arm/include/asm/dma.h +3 -1
@@ -16,7 +16,9 @@ struct device;static inline void *dma_alloc_coherent (struct device *dev,size_t size,dma_addr_t *dma_handle) { -void *ret =xmemalign (4096 , size); +void *ret =memalign (4096 , size); +if (!ret) +return NULL ;if (dma_handle) *dma_handle = (dma_addr_t )ret;
arch/mips/include/asm/dma.h +4 -1
@@ -30,7 +30,10 @@ static inline void *dma_alloc_coherent(struct device *dev,void *ptr;unsigned long virt; - ptr =xmemalign (PAGE_SIZE , size); + ptr =memalign (PAGE_SIZE , size); +if (!ptr) +return NULL ; +memset (ptr,0 , size); virt = (unsigned long )ptr;
arch/riscv/cpu/dma.c +3 -1
@@ -14,7 +14,9 @@ static void *__dma_alloc_coherent(struct device *dev, {void *ret; - ret =xmemalign (PAGE_SIZE , size); + ret =memalign (PAGE_SIZE , size); +if (!ret) +return NULL ;memset (ret,0 , size);
arch/sandbox/include/asm/dma.h +3 -1
@@ -20,7 +20,9 @@ struct device;static inline void *dma_alloc_coherent (struct device *dev,size_t size,dma_addr_t *dma_handle) { -void *ret =xmemalign (4096 , size); +void *ret =memalign (4096 , size); +if (!ret) +return NULL ;if (dma_handle) *dma_handle = (dma_addr_t )ret;
arch/x86/include/asm/dma.h +3 -2
@@ -6,7 +6,6 @@#include <linux/string.h> #include <linux/compiler.h> -#include <xfuncs.h> #include <malloc.h> struct device ;
@@ -19,7 +18,9 @@ struct device;static inline void *dma_alloc_coherent (struct device *dev,size_t size,dma_addr_t *dma_handle) { -void *ret =xmemalign (4096 , size); +void *ret =memalign (4096 , size); +if (!ret) +return NULL ;if (dma_handle) *dma_handle = (dma_addr_t )ret;
drivers/crypto/caam/caamrng.c +2 -0
@@ -211,6 +211,8 @@ static int caam_init_buf(struct caam_rng_ctx *ctx, int buf_id) bd->buf =dma_alloc_coherent (DMA_DEVICE_BROKEN ,RN_BUF_SIZE , &bd->addr); +if (!bd->buf) +return -ENOMEM ; err =rng_create_job_desc (ctx, buf_id);if (err)
drivers/crypto/caam/pbl-init.c +5 -2
@@ -454,11 +454,14 @@ int early_caam_init(struct caam_ctrl __iomem *_caam, bool is_imx)* PBL will only enable MMU right before unpacking, so all memory * is uncached and thus coherent here */ -if (IN_PBL ) +if (IN_PBL ) { g_jrdata = &pbl_jrdata; -else + }else { g_jrdata =dma_alloc_coherent (DMA_DEVICE_BROKEN ,sizeof (*g_jrdata),DMA_ADDRESS_BROKEN ); +if (!g_jrdata) +return -ENOMEM ; + } jr =IOMEM (caam) +0x1000 ; r4tst = &caam->r4tst[0 ];
drivers/dma/ti/k3-udma-am62l.c +4 -0
@@ -215,9 +215,13 @@ static int am62l_udma_request(struct dma *dma)if (uc->config.dir ==DMA_MEM_TO_DEV ) { uc->desc_tx =dma_alloc_coherent (DMA_DEVICE_BROKEN , ucc->hdesc_size,DMA_ADDRESS_BROKEN ); +if (!uc->desc_tx) +return -ENOMEM ; }else { uc->desc_rx =dma_alloc_coherent (DMA_DEVICE_BROKEN , ucc->hdesc_size *UDMA_RX_DESC_NUM ,DMA_ADDRESS_BROKEN ); +if (!uc->desc_rx) +return -ENOMEM ; } uc->in_use = true;
drivers/dma/ti/k3-udma.c +4 -0
@@ -1146,9 +1146,13 @@ static int udma_request(struct dma *dma)if (uc->config.dir ==DMA_MEM_TO_DEV ) { uc->desc_tx =dma_alloc_coherent (DMA_DEVICE_BROKEN , ucc->hdesc_size,DMA_ADDRESS_BROKEN ); +if (!uc->desc_tx) +return -ENOMEM ; }else { uc->desc_rx =dma_alloc_coherent (DMA_DEVICE_BROKEN , ucc->hdesc_size *UDMA_RX_DESC_NUM ,DMA_ADDRESS_BROKEN ); +if (!uc->desc_rx) +return -ENOMEM ; } uc->in_use = true;
drivers/firmware/qemu_fw_cfg.c +4 -0
@@ -338,6 +338,10 @@ static int fw_cfg_probe(struct device *dev) fw_cfg->acc_virt =dma_alloc_coherent (DMA_DEVICE_BROKEN ,sizeof (*fw_cfg->acc_virt), &fw_cfg->acc_dma); +if (!fw_cfg->acc_virt) { + ret = -ENOMEM ; + goto err; + } fw_cfg->cdev.name ="fw_cfg" ; fw_cfg->cdev.flags =DEVFS_IS_CHARACTER_DEV ;
drivers/net/ag71xx.c +5 -1
@@ -635,13 +635,17 @@ static int ag71xx_probe(struct device *dev)ag71xx_wr (priv,AG71XX_REG_FIFO_CFG5 , (0x66b82 ) | (1 <<19 ));ag71xx_wr (priv,AG71XX_REG_FIFO_CFG3 ,0x1f00140 ); - priv->rx_buffer =xmemalign (PAGE_SIZE ,NO_OF_RX_FIFOS *MAX_RBUFF_SZ ); + priv->rx_buffer =memalign (PAGE_SIZE ,NO_OF_RX_FIFOS *MAX_RBUFF_SZ ); priv->fifo_tx =dma_alloc_coherent (DMA_DEVICE_BROKEN ,NO_OF_TX_FIFOS *sizeof (ag7240_desc_t), &priv->addr_tx); priv->fifo_rx =dma_alloc_coherent (DMA_DEVICE_BROKEN ,NO_OF_RX_FIFOS *sizeof (ag7240_desc_t), &priv->addr_rx); + +if (!priv->rx_buffer || !priv->fifo_tx || !priv->fifo_rx) +return -ENOMEM ; + priv->next_tx =0 ; mac_l =0x3344 ;
drivers/net/arc_emac.c +3 -0
@@ -443,6 +443,9 @@ static int arc_emac_probe(struct device *dev) DMA_ADDRESS_BROKEN); priv->rxbuf =dma_alloc (RX_BD_NUM *PKTSIZE ); +if (!priv->rxbd || !priv->txbd || !priv->rxbuf) +return -ENOMEM ; +/* Set poll rate so that it polls every 1 ms */ arc_reg_set (priv,R_POLLRATE , clock_frequency /1000000 );
drivers/net/at91_ether.c +5 -0
@@ -318,9 +318,14 @@ static int at91_ether_probe(struct device *dev) ether_dev->rbf_framebuf =dma_alloc_coherent (DMA_DEVICE_BROKEN ,MAX_RX_DESCR *MAX_RBUFF_SZ ,DMA_ADDRESS_BROKEN ); +if (!ether_dev->rbf_framebuf) +return -ENOMEM ; + ether_dev->rbfdt =dma_alloc_coherent (DMA_DEVICE_BROKEN ,sizeof (struct rbf_t ) *MAX_RX_DESCR ,DMA_ADDRESS_BROKEN ); +if (!ether_dev->rbfdt) +return -ENOMEM ; ether_dev->phy_addr = pdata->phy_addr; miibus->read = at91_ether_mii_read;
drivers/net/e1000/main.c +2 -0
@@ -3595,6 +3595,8 @@ static int e1000_probe(struct pci_dev *pdev, const struct pci_device_id *id) 16 * sizeof(*hw->tx_base), &hw->tx_base_phys); hw->rx_base =dma_alloc_coherent (DMA_DEVICE_BROKEN ,16 *sizeof (*hw->rx_base), &hw->rx_base_phys); +if (!hw->tx_base || !hw->rx_base) +return -ENOMEM ; edev = &hw->edev;
drivers/net/fec_imx.c +5 -0
@@ -865,6 +865,11 @@ static int fec_probe(struct device *dev) base =dma_alloc_coherent (DMA_DEVICE_BROKEN ,FEC_XBD_SIZE ,DMA_ADDRESS_BROKEN ); +if (!base) { + ret = -ENOMEM ; + goto free_gpio; + } + fec->rbd_base = base; base +=FEC_RBD_NUM *sizeof (struct buffer_descriptor ); fec->tbd_base = base;
drivers/net/gianfar.c +7 -1
@@ -655,11 +655,17 @@ static int gfar_probe(struct device *dev) size = ((TX_BUF_CNT *sizeof (struct txbd8 )) + (RX_BUF_CNT *sizeof (struct rxbd8 )));if (IS_ENABLED (CONFIG_PPC )) { - base =xmemalign (BUF_ALIGN , size); + base =memalign (BUF_ALIGN , size); }else { base =dma_alloc_coherent (DMA_DEVICE_BROKEN , size,DMA_ADDRESS_BROKEN );dma_set_mask (dev,DMA_BIT_MASK (32 )); } + +if (!base) { + ret = -ENOMEM ; + goto free_received_packets; + } + priv->txbd = (struct txbd8 __iomem *)base; base +=TX_BUF_CNT *sizeof (struct txbd8 ); priv->rxbd = (struct rxbd8 __iomem *)base;
drivers/net/macb.c +8 -1
@@ -907,9 +907,16 @@ static int macb_probe(struct device *dev) macb->tx_ring =dma_alloc_coherent (DMA_DEVICE_BROKEN ,TX_RING_BYTES , &macb->tx_ring_phys); -if (macb->is_gem) +if (!macb->rx_ring || !macb->tx_ring) +return -ENOMEM ; + + +if (macb->is_gem) { macb->gem_q1_descs =dma_alloc_coherent (DMA_DEVICE_BROKEN ,GEM_Q1_DESC_BYTES , &macb->gem_q1_descs_phys); +if (!macb->gem_q1_descs) +return -ENOMEM ; + } macb->rx_packet_buf =net_alloc_packet ();
drivers/net/mvneta.c +9 -2
@@ -576,7 +576,7 @@ static void mvneta_init_rx_ring(struct mvneta_port *priv) priv->curr_rxdesc =0 ; } -static void mvneta_setup_tx_rx (struct mvneta_port *priv) +static int mvneta_setup_tx_rx (struct mvneta_port *priv) {u32 val;
@@ -590,6 +590,9 @@ static void mvneta_setup_tx_rx(struct mvneta_port *priv) DMA_ADDRESS_BROKEN); priv->rxbuf =dma_alloc (RX_RING_SIZE *ALIGN (PKTSIZE ,8 )); +if (!priv->txdesc || !priv->rxdesc || !priv->rxbuf) +return -ENOMEM ; +mvneta_init_rx_ring (priv);/* Configure the Rx queue */
@@ -610,6 +613,8 @@ static void mvneta_setup_tx_rx(struct mvneta_port *priv)/* Set the number of available Rx descriptors */ writel (RX_RING_SIZE <<MVNETA_RXQ_ADD_NON_OCCUPIED_SHIFT , priv->reg +MVNETA_RXQ_STATUS_UPDATE_REG (0 )); + +return 0 ; }static int mvneta_port_config (struct mvneta_port *priv)
@@ -730,7 +735,9 @@ static int mvneta_probe(struct device *dev)return ret;mvneta_conf_mbus_windows (priv); -mvneta_setup_tx_rx (priv); + ret =mvneta_setup_tx_rx (priv); +if (ret) +return ret;/* register eth device */ priv->edev.priv = priv;
drivers/net/orion-gbe.c +4 -0
@@ -409,6 +409,10 @@ static int port_probe(struct device *parent, struct port_priv *port)RX_RING_SIZE *ALIGN (sizeof (*port->rxdesc),16 ), DMA_ADDRESS_BROKEN); + +if (!port->txdesc || !port->rxdesc) +return -ENOMEM ; + port->rxbuf =dma_alloc (RX_RING_SIZE *ALIGN (PKTSIZE ,8 ));port_stop (port);
drivers/net/r8169_main.c +15 -2
@@ -2874,7 +2874,7 @@ static int rtl8169_init_dev(struct eth_device *edev)#define ETH_ZLEN 60/* Min. octets in frame sans FCS */ #define PKT_BUF_SIZE 1536 -static void rtl8169_init_ring (struct rtl8169_private *tp) +static int rtl8169_init_ring (struct rtl8169_private *tp) {struct eth_device *edev = &tp->edev;int i;
@@ -2884,14 +2884,22 @@ static void rtl8169_init_ring(struct rtl8169_private *tp) tp->TxDescArray =dma_alloc_coherent (DMA_DEVICE_BROKEN ,NUM_TX_DESC *sizeof (struct TxDesc ), &tp->TxPhyAddr); +if (!tp->TxDescArray) +return -ENOMEM ; + tp->tx_buf =dma_alloc (NUM_TX_DESC *PKT_BUF_SIZE ); + tp->tx_buf_phys =dma_map_single (edev->parent, tp->tx_buf,NUM_TX_DESC *PKT_BUF_SIZE ,DMA_TO_DEVICE ); tp->RxDescArray =dma_alloc_coherent (DMA_DEVICE_BROKEN ,NUM_RX_DESC *sizeof (struct RxDesc ), &tp->RxPhyAddr); +if (!tp->RxDescArray) +return -ENOMEM ; + tp->rx_buf =dma_alloc (NUM_RX_DESC *PKT_BUF_SIZE ); + tp->rx_buf_phys =dma_map_single (edev->parent, tp->rx_buf,NUM_RX_DESC *PKT_BUF_SIZE ,DMA_FROM_DEVICE );
@@ -2906,6 +2914,8 @@ static void rtl8169_init_ring(struct rtl8169_private *tp) tp->RxDescArray[i].addr =cpu_to_le64 (tp->rx_buf_phys + i *PKT_BUF_SIZE ); } + +return 0 ; }static void r8169_phylink_handler (struct eth_device *edev)
@@ -2922,7 +2932,10 @@ static int rtl8169_eth_open(struct eth_device *edev)pci_set_master (tp->pci_dev); -rtl8169_init_ring (tp); + ret =rtl8169_init_ring (tp); +if (ret) +return ret; +rtl_hw_start (tp); ret = phy_device_connect(edev, &tp->miibus, 0, r8169_phylink_handler, 0,
drivers/net/rtl8139.c +3 -0
@@ -386,6 +386,9 @@ static int rtl8139_eth_open(struct eth_device *edev) &priv->tx_bufs_dma); priv->rx_ring =dma_alloc_coherent (DMA_DEVICE_BROKEN ,RX_BUF_TOT_LEN , &priv->rx_ring_dma); +if (!priv->tx_bufs || !priv->rx_ring) +return -ENOMEM ; + priv->tx_flag = (TX_FIFO_THRESH <<11 ) &0x003f0000 ;rtl8139_init_ring (priv);
drivers/soc/starfive/jh7100_dma.c +3 -1
@@ -16,7 +16,9 @@ static inline void *jh7100_alloc_coherent(struct device *dev,dma_addr_t cpu_base;void *ret; - ret =xmemalign (PAGE_SIZE , size); + ret =memalign (PAGE_SIZE , size); +if (!ret) +return NULL ;memset (ret,0 , size);
drivers/usb/host/ehci-hcd.c +10 -0
@@ -915,6 +915,8 @@ static int ehci_init(struct usb_host *host)*/ ehci->periodic_list =dma_alloc_coherent (DMA_DEVICE_BROKEN ,1024 *4 , &ehci->periodic_list_dma); +if (ehci->periodic_list ==NULL ) +return -ENOMEM ;for (i =0 ; i <1024 ; i++) { ehci->periodic_list[i] =cpu_to_hc32 ((unsigned long )ehci->periodic_queue_dma |QH_LINK_TYPE_QH );
@@ -1134,11 +1136,16 @@ static struct int_queue *ehci_create_int_queue(struct usb_device *dev, result->first =dma_alloc_coherent (DMA_DEVICE_BROKEN ,sizeof (struct QH ) * queuesize, &result->first_dma); +if (!result->first) +return NULL ; + result->current = result->first; result->last = result->first + queuesize -1 ; result->tds =dma_alloc_coherent (DMA_DEVICE_BROKEN ,sizeof (struct qTD ) * queuesize, &result->tds_dma); +if (!result->tds) +return NULL ;for (i =0 ; i < queuesize; i++) {struct QH *qh = result->first + i;
@@ -1379,6 +1386,9 @@ struct ehci_host *ehci_register(struct device *dev, struct ehci_data *data)sizeof (struct qTD ) *NUM_TD , &ehci->td_dma); +if (!ehci->qh_list || !ehci->periodic_queue || !ehci->td) +return NULL ; + host->hw_dev = dev; host->init = ehci_init; host->usbphy = data->usbphy;
drivers/video/atmel_lcdfb_core.c +6 -1
@@ -476,10 +476,15 @@ int atmel_lcdc_register(struct device *dev, struct atmel_lcdfb_devdata *data)atmel_lcdfb_start_clock (sinfo); -if (data->dma_desc_size) +if (data->dma_desc_size) { sinfo->dma_desc =dma_alloc_coherent (DMA_DEVICE_BROKEN , data->dma_desc_size,DMA_ADDRESS_BROKEN ); +if (!sinfo->dma_desc) { + ret = -ENOMEM ; + goto stop_clk; + } + } info->dev.parent = dev; ret =register_framebuffer (info);
drivers/video/pxa.c +5 -0
@@ -520,9 +520,14 @@ static int pxafb_probe(struct device *dev) DMA_ADDRESS_BROKEN), PAGE_SIZE); +if (!fbi->info.screen_base) +return -ENOMEM ; + fbi->dma_buff =PTR_ALIGN (dma_alloc_coherent (DMA_DEVICE_BROKEN ,sizeof (struct pxafb_dma_buff ) +16 ,DMA_ADDRESS_BROKEN ),16 ); +if (!fbi->dma_buff) +return -ENOMEM ;pxafb_activate_var (fbi);
drivers/video/ramfb.c +2 -0
@@ -41,6 +41,8 @@ static int ramfb_activate_var(struct fb_info *fbi) fbi->screen_size = fbi->xres * fbi->yres * fbi->bits_per_pixel /BITS_PER_BYTE ; fbi->screen_base =dma_alloc_coherent (hwdev, fbi->screen_size, &ramfb->screen_dma); +if (!fbi->screen_base) +return -ENOMEM ;return 0 ; }
Signature · 1 line
2.47.3
Quoted 9 lines · Ahmad Fatoum
The majority of our calls to
dma_alloc_coherentcheck for a NULL return that would indicate an error as that's the Linux API as well.In barebox,
dma_alloc_coherentpanics though. This mostly doesn't matter, because these are mostly fixed size allocations at driver probe time, but we have some older code like the Freescale UDC driver that allocates coherent memory out of a poller context.[...]
Applied, thanks!
[1/1] dma: return NULL on dma_alloc_coherent failure
https://git.pengutronix.de/cgit/barebox/commit/?id=467f5e1cc300 (link may not be stable)
Best regards,
Signature · 1 line
Sascha Hauer <[email protected]>