remove pci_dma_* abuses and workarounds V2
Subsystems (4)
Back before the dawn of time pci_dma_* with a NULL pci_dev argument was used for all kinds of things, e.g. dma mapping for non-PCI devices. All this has been long removed, but it turns out we still care for a NULL pci_dev in the wrappers, and we still have two odd USB drivers that use pci_dma_alloc_consistent for allocating memory while ignoring the dma_addr_t entirely, and a network driver mixing the already wrong usage of dma_* with a NULL device with a single call to pci_free_consistent.
This series switches the two usb drivers to use plain kzalloc, the net driver to properly use the dma API and then removes the handling of the NULL pci_dev in the pci_dma_* wrappers.
Changes since V1:
- remove allocation failure printks
- use kcalloc
- fix tsi108_eth
- improve changelogs
PATCH 1/4 media/ttusb-budget: remove pci_zalloc_coherent abuse
Switch to a plain kzalloc instead of pci_zalloc_coherent to allocate memory for the USB DMA.
--- drivers/media/usb/ttusb-budget/dvb-ttusb-budget.c | 18 ++++-------------- 1 file changed, 4 insertions(+), 14 deletions(-)
drivers/media/usb/ttusb-budget/dvb-ttusb-budget.c +4 -14
@@ -102,7 +102,6 @@ struct ttusb {unsigned int isoc_in_pipe;void *iso_buffer; -dma_addr_t iso_dma_handle;struct urb *iso_urb[ISO_BUF_COUNT ];
@@ -792,26 +791,17 @@ static void ttusb_free_iso_urbs(struct ttusb *ttusb)for (i =0 ; i <ISO_BUF_COUNT ; i++)usb_free_urb (ttusb->iso_urb[i]); - -pci_free_consistent (NULL , -ISO_FRAME_SIZE *FRAMES_PER_ISO_BUF * -ISO_BUF_COUNT , ttusb->iso_buffer, - ttusb->iso_dma_handle); +kfree (ttusb->iso_buffer); }static int ttusb_alloc_iso_urbs (struct ttusb *ttusb) {int i; - ttusb->iso_buffer =pci_zalloc_consistent (NULL , -ISO_FRAME_SIZE *FRAMES_PER_ISO_BUF *ISO_BUF_COUNT , - &ttusb->iso_dma_handle); - -if (!ttusb->iso_buffer) { -dprintk ("%s: pci_alloc_consistent - not enough memory\n" , - __func__); + ttusb->iso_buffer =kcalloc (FRAMES_PER_ISO_BUF *ISO_BUF_COUNT , +ISO_FRAME_SIZE ,GFP_KERNEL ); +if (!ttusb->iso_buffer)return -ENOMEM ; - }for (i =0 ; i <ISO_BUF_COUNT ; i++) {struct urb *urb;
Signature · 1 line
2.14.2
PATCH 2/4 media/ttusb-dev: remove pci_zalloc_coherent abuse
In reply to Christoph HellwigSwitch to a plain kzalloc instead of pci_zalloc_coherent to allocate memory for the USB DMA.
--- drivers/media/usb/ttusb-dec/ttusb_dec.c | 18 ++++-------------- 1 file changed, 4 insertions(+), 14 deletions(-)
drivers/media/usb/ttusb-dec/ttusb_dec.c +4 -14
@@ -127,7 +127,6 @@ struct ttusb_dec {struct urb *irq_urb;dma_addr_t irq_dma_handle;void *iso_buffer; -dma_addr_t iso_dma_handle;struct urb *iso_urb[ISO_BUF_COUNT ];int iso_stream_count;struct mutex iso_mutex;
@@ -1185,11 +1184,7 @@ static void ttusb_dec_free_iso_urbs(struct ttusb_dec *dec)for (i =0 ; i <ISO_BUF_COUNT ; i++)usb_free_urb (dec->iso_urb[i]); - -pci_free_consistent (NULL , -ISO_FRAME_SIZE * (FRAMES_PER_ISO_BUF * -ISO_BUF_COUNT ), - dec->iso_buffer, dec->iso_dma_handle); +kfree (dec->iso_buffer); }static int ttusb_dec_alloc_iso_urbs (struct ttusb_dec *dec)
@@ -1198,15 +1193,10 @@ static int ttusb_dec_alloc_iso_urbs(struct ttusb_dec *dec)dprintk ("%s\n" , __func__); - dec->iso_buffer =pci_zalloc_consistent (NULL , -ISO_FRAME_SIZE * (FRAMES_PER_ISO_BUF *ISO_BUF_COUNT ), - &dec->iso_dma_handle); - -if (!dec->iso_buffer) { -dprintk ("%s: pci_alloc_consistent - not enough memory\n" , - __func__); + dec->iso_buffer =kcalloc (FRAMES_PER_ISO_BUF *ISO_BUF_COUNT , +ISO_FRAME_SIZE ,GFP_KERNEL ); +if (!dec->iso_buffer)return -ENOMEM ; - }for (i =0 ; i <ISO_BUF_COUNT ; i++) {struct urb *urb;
Signature · 1 line
2.14.2
PATCH 3/4 tsi108_eth: use dma API properly
In reply to Christoph HellwigWe need to pass a struct device to the dma API, even if some architectures still support that for legacy reasons, and should not mix it with the old PCI dma API.
Note that the driver also seems to never actually unmap its dma mappings, but to fix that we'll need someone more familar with the driver.
--- drivers/net/ethernet/tundra/tsi108_eth.c | 36 ++++++++++++++++++-------------- 1 file changed, 20 insertions(+), 16 deletions(-)
drivers/net/ethernet/tundra/tsi108_eth.c +20 -16
@@ -152,6 +152,8 @@ struct tsi108_prv_data {u32 msg_enable;/* debug message level */ struct mii_if_info mii_if;unsigned int init_media; + +struct platform_device *pdev; };/* Structure for a device driver */
@@ -703,17 +705,18 @@ static int tsi108_send_packet(struct sk_buff * skb, struct net_device *dev) data->txskbs[tx] = skb;if (i ==0 ) { - data->txring[tx].buf0 =dma_map_single (NULL , skb->data, -skb_headlen (skb),DMA_TO_DEVICE ); + data->txring[tx].buf0 =dma_map_single (&data->pdev->dev, + skb->data,skb_headlen (skb), +DMA_TO_DEVICE ); data->txring[tx].len =skb_headlen (skb); misc |=TSI108_TX_SOF ; }else {const skb_frag_t *frag = &skb_shinfo (skb)->frags[i -1 ]; - data->txring[tx].buf0 =skb_frag_dma_map (NULL , frag, -0 , -skb_frag_size (frag), -DMA_TO_DEVICE ); + data->txring[tx].buf0 = +skb_frag_dma_map (&data->pdev->dev, frag, +0 ,skb_frag_size (frag), +DMA_TO_DEVICE ); data->txring[tx].len =skb_frag_size (frag); }
@@ -808,9 +811,9 @@ static int tsi108_refill_rx(struct net_device *dev, int budget)if (!skb)break ; - data->rxring[rx].buf0 =dma_map_single (NULL , skb->data, -TSI108_RX_SKB_SIZE , -DMA_FROM_DEVICE ); + data->rxring[rx].buf0 =dma_map_single (&data->pdev->dev, + skb->data,TSI108_RX_SKB_SIZE , +DMA_FROM_DEVICE );/* Sometimes the hardware sets blen to zero after packet * reception, even though the manual says that it's only ever
@@ -1308,15 +1311,15 @@ static int tsi108_open(struct net_device *dev) data->id, dev->irq, dev->name); } - data->rxring =dma_zalloc_coherent (NULL , rxring_size, &data->rxdma, -GFP_KERNEL ); + data->rxring =dma_zalloc_coherent (&data->pdev->dev, rxring_size, + &data->rxdma,GFP_KERNEL );if (!data->rxring)return -ENOMEM ; - data->txring =dma_zalloc_coherent (NULL , txring_size, &data->txdma, -GFP_KERNEL ); + data->txring =dma_zalloc_coherent (&data->pdev->dev, txring_size, + &data->txdma,GFP_KERNEL );if (!data->txring) { -pci_free_consistent (NULL , rxring_size, data->rxring, +dma_free_coherent (&data->pdev->dev, rxring_size, data->rxring, data->rxdma);return -ENOMEM ; }
@@ -1428,10 +1431,10 @@ static int tsi108_close(struct net_device *dev)dev_kfree_skb (skb); } -dma_free_coherent (0 , +dma_free_coherent (&data->pdev->dev,TSI108_RXRING_LEN *sizeof (rx_desc), data->rxring, data->rxdma); -dma_free_coherent (0 , +dma_free_coherent (&data->pdev->dev,TSI108_TXRING_LEN *sizeof (tx_desc), data->txring, data->txdma);
@@ -1576,6 +1579,7 @@ tsi108_init_one(struct platform_device *pdev)printk ("tsi108_eth%d: probe...\n" , pdev->id); data =netdev_priv (dev); data->dev = dev; + data->pdev = pdev; pr_debug("tsi108_eth%d:regs:phyresgs:phy:irq_num=0x%x:0x%x:0x%x:0x%x\n", pdev->id, einfo->regs, einfo->phyregs,
Signature · 1 line
2.14.2
Re: [PATCH 3/4] tsi108_eth: use dma API properly
Quoted 8 lines · Christoph Hellwig
We need to pass a struct device to the dma API, even if some architectures still support that for legacy reasons, and should not mix it with the old PCI dma API.
Note that the driver also seems to never actually unmap its dma mappings, but to fix that we'll need someone more familar with the driver.
+ struct
platform_device*pdev;
Do you really need platform_defice reference?
Perhaps
struct device *hdev; // hardware device
data->hdev = &pdev->dev;
Another idea
dev->dev.parent = &pdev->dev;
No new member needed.
Quoted 86 lines
};
/* Structure for a device driver */
drivers/net/ethernet/tundra/tsi108_eth.c +18
-17@@ -703,17 +705,18 @@ static int tsi108_send_packet(struct sk_buff * skb, struct net_device *dev) data->txskbs[tx] = skb;if (i ==0 ) { - data->txring[tx].buf0 =dma_map_single (NULL , skb->data, -skb_headlen (skb),DMA_TO_DEVICE ); + data->txring[tx].buf0 =dma_map_single (&data->pdev->dev, + skb->data,skb_headlen (skb), +DMA_TO_DEVICE ); data->txring[tx].len =skb_headlen (skb); misc |=TSI108_TX_SOF ; }else {const skb_frag_t *frag = &skb_shinfo (skb)->frags[i -1 ]; - data->txring[tx].buf0 =skb_frag_dma_map (NULL , frag, -0 , -skb_frag_size (frag), -DMA_TO_DEVICE ); + data->txring[tx].buf0 = +skb_frag_dma_map (&data->pdev->dev, frag, +0 ,skb_frag_size (frag), +DMA_TO_DEVICE ); data->txring[tx].len =skb_frag_size (frag); }@@ -808,9 +811,9 @@ static int tsi108_refill_rx(struct net_device *dev, int budget)if (!skb)break ; - data->rxring[rx].buf0 =dma_map_single (NULL , skb->data, -TSI108_RX_SKB_SIZE , -DMA_FROM_DEVICE ); + data->rxring[rx].buf0 =dma_map_single (&data->pdev->dev, + skb->data,TSI108_RX_SKB_SIZE , +DMA_FROM_DEVICE );/* Sometimes the hardware sets blen to zero after packet * reception, even though the manual says that it's only ever @@ -1308,15 +1311,15 @@ static int tsi108_open(struct net_device *dev) data->id, dev->irq, dev->name); } - data->rxring =dma_zalloc_coherent (NULL , rxring_size, &data->rxdma, -GFP_KERNEL ); + data->rxring =dma_zalloc_coherent (&data->pdev->dev, rxring_size, + &data->rxdma,GFP_KERNEL );if (!data->rxring)return -ENOMEM ; - data->txring =dma_zalloc_coherent (NULL , txring_size, &data->txdma, -GFP_KERNEL ); + data->txring =dma_zalloc_coherent (&data->pdev->dev, txring_size, + &data->txdma,GFP_KERNEL );if (!data->txring) { -pci_free_consistent (NULL , rxring_size, data->rxring, +dma_free_coherent (&data->pdev->dev, rxring_size, data->rxring, data->rxdma);return -ENOMEM ; }@@ -1428,10 +1431,10 @@ static int tsi108_close(struct net_device *dev)dev_kfree_skb (skb); } -dma_free_coherent (0 , +dma_free_coherent (&data->pdev->dev,TSI108_RXRING_LEN *sizeof (rx_desc), data->rxring, data->rxdma); -dma_free_coherent (0 , +dma_free_coherent (&data->pdev->dev,TSI108_TXRING_LEN *sizeof (tx_desc), data->txring, data->txdma);@@ -1576,6 +1579,7 @@ tsi108_init_one(struct platform_device *pdev)printk ("tsi108_eth%d: probe...\n" , pdev->id); data =netdev_priv (dev); data->dev = dev; + data->pdev = pdev; pr_debug("tsi108_eth%d:regs:phyresgs:phy:irq_num=0x%x:0x%x:0x%x:0x%x\n", pdev->id, einfo->regs, einfo->phyregs, --2.14.2
Signature · 2 lines
With Best Regards, Andy Shevchenko
Re: [PATCH 3/4] tsi108_eth: use dma API properly
Quoted 9 lines · Andy Shevchenko
Quoted 1 line
+ struct
platform_device*pdev;Do you really need
platform_deficereference?Perhaps
struct device *hdev; // hardware device
Quoted 7 lines
data->hdev=&pdev->dev;Another idea
dev->dev.parent=&pdev->dev;No new member needed.
Maybe. But what I've done is the simplest change in a long obsolete driver that I don't understand at all. I'd rather keep it simple.
Re: [PATCH 3/4] tsi108_eth: use dma API properly
In reply to Christoph Hellwig[+cc David, FYI, I plan to merge this via PCI along with the rest of Christoph's series]
Quoted 108 lines · Christoph Hellwig
We need to pass a struct device to the dma API, even if some architectures still support that for legacy reasons, and should not mix it with the old PCI dma API.
Note that the driver also seems to never actually unmap its dma mappings, but to fix that we'll need someone more familar with the driver.
Signed-off-by Christoph Hellwig <[email protected]>--- drivers/net/ethernet/tundra/tsi108_eth.c | 36 ++++++++++++++++++-------------- 1 file changed, 20 insertions(+), 16 deletions(-)drivers/net/ethernet/tundra/tsi108_eth.c +20
-16@@ -152,6 +152,8 @@ struct tsi108_prv_data {u32 msg_enable;/* debug message level */ struct mii_if_info mii_if;unsigned int init_media; + +struct platform_device *pdev; };/* Structure for a device driver */ @@ -703,17 +705,18 @@ static int tsi108_send_packet(struct sk_buff * skb, struct net_device *dev) data->txskbs[tx] = skb;if (i ==0 ) { - data->txring[tx].buf0 =dma_map_single (NULL , skb->data, -skb_headlen (skb),DMA_TO_DEVICE ); + data->txring[tx].buf0 =dma_map_single (&data->pdev->dev, + skb->data,skb_headlen (skb), +DMA_TO_DEVICE ); data->txring[tx].len =skb_headlen (skb); misc |=TSI108_TX_SOF ; }else {const skb_frag_t *frag = &skb_shinfo (skb)->frags[i -1 ]; - data->txring[tx].buf0 =skb_frag_dma_map (NULL , frag, -0 , -skb_frag_size (frag), -DMA_TO_DEVICE ); + data->txring[tx].buf0 = +skb_frag_dma_map (&data->pdev->dev, frag, +0 ,skb_frag_size (frag), +DMA_TO_DEVICE ); data->txring[tx].len =skb_frag_size (frag); }@@ -808,9 +811,9 @@ static int tsi108_refill_rx(struct net_device *dev, int budget)if (!skb)break ; - data->rxring[rx].buf0 =dma_map_single (NULL , skb->data, -TSI108_RX_SKB_SIZE , -DMA_FROM_DEVICE ); + data->rxring[rx].buf0 =dma_map_single (&data->pdev->dev, + skb->data,TSI108_RX_SKB_SIZE , +DMA_FROM_DEVICE );/* Sometimes the hardware sets blen to zero after packet * reception, even though the manual says that it's only ever @@ -1308,15 +1311,15 @@ static int tsi108_open(struct net_device *dev) data->id, dev->irq, dev->name); } - data->rxring =dma_zalloc_coherent (NULL , rxring_size, &data->rxdma, -GFP_KERNEL ); + data->rxring =dma_zalloc_coherent (&data->pdev->dev, rxring_size, + &data->rxdma,GFP_KERNEL );if (!data->rxring)return -ENOMEM ; - data->txring =dma_zalloc_coherent (NULL , txring_size, &data->txdma, -GFP_KERNEL ); + data->txring =dma_zalloc_coherent (&data->pdev->dev, txring_size, + &data->txdma,GFP_KERNEL );if (!data->txring) { -pci_free_consistent (NULL , rxring_size, data->rxring, +dma_free_coherent (&data->pdev->dev, rxring_size, data->rxring, data->rxdma);return -ENOMEM ; }@@ -1428,10 +1431,10 @@ static int tsi108_close(struct net_device *dev)dev_kfree_skb (skb); } -dma_free_coherent (0 , +dma_free_coherent (&data->pdev->dev,TSI108_RXRING_LEN *sizeof (rx_desc), data->rxring, data->rxdma); -dma_free_coherent (0 , +dma_free_coherent (&data->pdev->dev,TSI108_TXRING_LEN *sizeof (tx_desc), data->txring, data->txdma);@@ -1576,6 +1579,7 @@ tsi108_init_one(struct platform_device *pdev)printk ("tsi108_eth%d: probe...\n" , pdev->id); data =netdev_priv (dev); data->dev = dev; + data->pdev = pdev; pr_debug("tsi108_eth%d:regs:phyresgs:phy:irq_num=0x%x:0x%x:0x%x:0x%x\n", pdev->id, einfo->regs, einfo->phyregs,Signature · 1 line
2.14.2
David Miller
maintainerRe: [PATCH 3/4] tsi108_eth: use dma API properly
From: Bjorn Helgaas <[email protected]>
Date: Wed, 17 Jan 2018 18:08:18 -0600
Quoted 2 lines
[+cc David, FYI, I plan to merge this via PCI along with the rest of Christoph's series]
No problem.
PATCH 4/4 PCI: Remove NULL device handling from PCI DMA API
In reply to Christoph HellwigHistorically some ISA drivers used the old PCI DMA API with a NULL pdev argument, but these days this isn't used and not too useful due to the per-device DMA ops, so remove it.
--- include/linux/pci-dma-compat.h | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-)
include/linux/pci-dma-compat.h +13 -14
@@ -17,91 +17,90 @@ static inline void * pci_alloc_consistent(struct pci_dev *hwdev, size_t size, dma_addr_t *dma_handle) { - return dma_alloc_coherent(hwdev == NULL ? NULL : &hwdev->dev, size, dma_handle, GFP_ATOMIC); + return dma_alloc_coherent(&hwdev->dev, size, dma_handle, GFP_ATOMIC); }static inline void *pci_zalloc_consistent (struct pci_dev *hwdev,size_t size,dma_addr_t *dma_handle) { -return dma_zalloc_coherent (hwdev ==NULL ?NULL : &hwdev->dev, - size, dma_handle,GFP_ATOMIC ); +return dma_zalloc_coherent (&hwdev->dev, size, dma_handle,GFP_ATOMIC ); }static inline void pci_free_consistent (struct pci_dev *hwdev,size_t size,void *vaddr,dma_addr_t dma_handle) { -dma_free_coherent (hwdev ==NULL ?NULL : &hwdev->dev, size, vaddr, dma_handle); +dma_free_coherent (&hwdev->dev, size, vaddr, dma_handle); }static inline dma_addr_t pci_map_single (struct pci_dev *hwdev,void *ptr,size_t size,int direction) { -return dma_map_single (hwdev ==NULL ?NULL : &hwdev->dev, ptr, size, (enum dma_data_direction )direction); +return dma_map_single (&hwdev->dev, ptr, size, (enum dma_data_direction )direction); }static inline void pci_unmap_single (struct pci_dev *hwdev,dma_addr_t dma_addr,size_t size,int direction) { -dma_unmap_single (hwdev ==NULL ?NULL : &hwdev->dev, dma_addr, size, (enum dma_data_direction )direction); +dma_unmap_single (&hwdev->dev, dma_addr, size, (enum dma_data_direction )direction); }static inline dma_addr_t pci_map_page (struct pci_dev *hwdev,struct page *page,unsigned long offset,size_t size,int direction) { -return dma_map_page (hwdev ==NULL ?NULL : &hwdev->dev, page, offset, size, (enum dma_data_direction )direction); +return dma_map_page (&hwdev->dev, page, offset, size, (enum dma_data_direction )direction); }static inline void pci_unmap_page (struct pci_dev *hwdev,dma_addr_t dma_address,size_t size,int direction) { -dma_unmap_page (hwdev ==NULL ?NULL : &hwdev->dev, dma_address, size, (enum dma_data_direction )direction); +dma_unmap_page (&hwdev->dev, dma_address, size, (enum dma_data_direction )direction); }static inline int pci_map_sg (struct pci_dev *hwdev,struct scatterlist *sg,int nents,int direction) { -return dma_map_sg (hwdev ==NULL ?NULL : &hwdev->dev, sg, nents, (enum dma_data_direction )direction); +return dma_map_sg (&hwdev->dev, sg, nents, (enum dma_data_direction )direction); }static inline void pci_unmap_sg (struct pci_dev *hwdev,struct scatterlist *sg,int nents,int direction) { -dma_unmap_sg (hwdev ==NULL ?NULL : &hwdev->dev, sg, nents, (enum dma_data_direction )direction); +dma_unmap_sg (&hwdev->dev, sg, nents, (enum dma_data_direction )direction); }static inline void pci_dma_sync_single_for_cpu (struct pci_dev *hwdev,dma_addr_t dma_handle,size_t size,int direction) { -dma_sync_single_for_cpu (hwdev ==NULL ?NULL : &hwdev->dev, dma_handle, size, (enum dma_data_direction )direction); +dma_sync_single_for_cpu (&hwdev->dev, dma_handle, size, (enum dma_data_direction )direction); }static inline void pci_dma_sync_single_for_device (struct pci_dev *hwdev,dma_addr_t dma_handle,size_t size,int direction) { -dma_sync_single_for_device (hwdev ==NULL ?NULL : &hwdev->dev, dma_handle, size, (enum dma_data_direction )direction); +dma_sync_single_for_device (&hwdev->dev, dma_handle, size, (enum dma_data_direction )direction); }static inline void pci_dma_sync_sg_for_cpu (struct pci_dev *hwdev,struct scatterlist *sg,int nelems,int direction) { -dma_sync_sg_for_cpu (hwdev ==NULL ?NULL : &hwdev->dev, sg, nelems, (enum dma_data_direction )direction); +dma_sync_sg_for_cpu (&hwdev->dev, sg, nelems, (enum dma_data_direction )direction); }static inline void pci_dma_sync_sg_for_device (struct pci_dev *hwdev,struct scatterlist *sg,int nelems,int direction) { -dma_sync_sg_for_device (hwdev ==NULL ?NULL : &hwdev->dev, sg, nelems, (enum dma_data_direction )direction); +dma_sync_sg_for_device (&hwdev->dev, sg, nelems, (enum dma_data_direction )direction); } static inline int
Signature · 1 line
2.14.2
Bjorn Helgaas
Applied[+cc David]
Quoted 13 lines · Christoph Hellwig
Back before the dawn of time pci_dma_* with a NULL
pci_devargument was used for all kinds of things, e.g. dma mapping for non-PCI devices. All this has been long removed, but it turns out we still care for a NULLpci_devin the wrappers, and we still have two odd USB drivers that usepci_dma_alloc_consistentfor allocating memory while ignoring thedma_addr_tentirely, and a network driver mixing the already wrong usage of dma_* with a NULL device with a single call topci_free_consistent.This series switches the two usb drivers to use plain kzalloc, the net driver to properly use the dma API and then removes the handling of the NULL
pci_devin the pci_dma_* wrappers.
Quoted 5 lines
Changes since V1:
- remove allocation failure printks
- use kcalloc
- fixtsi108_eth
- improve changelogs
Applied to pci/dma for v4.16, thanks!