[PATCH] pci_set_dac helper

From: Jeff Garzik (jgarzik_at_pobox.com)
Date: 12/31/03

  • Next message: Ben Collins: "Re: 2.6.1-rc1-mm1 - ieee1394 broken again?"
    Date:	Wed, 31 Dec 2003 11:12:42 -0500
    To: Linux Kernel <linux-kernel@vger.kernel.org>
    
    
    

    It seems to me like a lot of drivers wind up getting their
    pci_set_dma_mask stuff wrong, occasionally in subtle ways. So, I
    created a "give me 64-bit PCI DMA" helper function.

    The attached patch demonstrates its use in tg3, from which the logic
    originated. It also fixes a tiny bug in tg3, whereby it might return
    zero on error (rather than -EFOO) if the pci_set_dma_mask succeeds but
    pci_set_consistent_dma_mask fails.

    
    

    ===== drivers/net/tg3.c 1.112 vs edited =====
    --- 1.112/drivers/net/tg3.c Thu Nov 20 12:46:05 2003
    +++ edited/drivers/net/tg3.c Wed Dec 31 11:06:43 2003
    @@ -7493,7 +7493,8 @@
             unsigned long tg3reg_base, tg3reg_len;
             struct net_device *dev;
             struct tg3 *tp;
    - int i, err, pci_using_dac, pm_cap;
    + int i, err, pm_cap;
    + u32 dac_flags;
     
             if (tg3_version_printed++ == 0)
                     printk(KERN_INFO "%s", version);
    @@ -7530,21 +7531,16 @@
             }
     
             /* Configure DMA attributes. */
    - if (!pci_set_dma_mask(pdev, 0xffffffffffffffffULL)) {
    - pci_using_dac = 1;
    - if (pci_set_consistent_dma_mask(pdev, 0xffffffffffffffffULL)) {
    - printk(KERN_ERR PFX "Unable to obtain 64 bit DMA "
    - "for consistent allocations\n");
    - goto err_out_free_res;
    - }
    - } else {
    - err = pci_set_dma_mask(pdev, 0xffffffffULL);
    - if (err) {
    - printk(KERN_ERR PFX "No usable DMA configuration, "
    - "aborting.\n");
    - goto err_out_free_res;
    - }
    - pci_using_dac = 0;
    + dac_flags = 0;
    + err = pci_set_dac(pdev, &dac_flags);
    + if (err)
    + goto err_out_free_res;
    +
    + if ((dac_flags & (PCI_DAC_EN | PCI_DAC_CONS_EN)) == PCI_DAC_EN) {
    + printk(KERN_ERR PFX "Unable to obtain 64 bit DMA "
    + "for consistent allocations\n");
    + err = -EIO;
    + goto err_out_free_res;
             }
     
             tg3reg_base = pci_resource_start(pdev, 0);
    @@ -7560,7 +7556,7 @@
             SET_MODULE_OWNER(dev);
             SET_NETDEV_DEV(dev, &pdev->dev);
     
    - if (pci_using_dac)
    + if (dac_flags)
                     dev->features |= NETIF_F_HIGHDMA;
     #if TG3_VLAN_TAG_USED
             dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;
    ===== drivers/pci/pci.c 1.60 vs edited =====
    --- 1.60/drivers/pci/pci.c Sun Oct 5 04:07:55 2003
    +++ edited/drivers/pci/pci.c Wed Dec 31 11:00:44 2003
    @@ -713,7 +713,32 @@
     
             return 0;
     }
    -
    +
    +int
    +pci_set_dac(struct pci_dev *dev, u32 *flags_out)
    +{
    + int err = 0;
    + u32 flags = 0;
    +
    + if (!pci_set_dma_mask(dev, 0xffffffffffffffffULL)) {
    + flags |= PCI_DAC_EN;
    + if (pci_set_consistent_dma_mask(dev, 0xffffffffffffffffULL))
    + printk(KERN_WARNING
    + "PCI(%s): Unable to obtain 64 bit DMA "
    + "for consistent allocations\n", pci_name(dev));
    + else
    + flags |= PCI_DAC_CONS_EN;
    + } else {
    + err = pci_set_dma_mask(dev, 0xffffffffULL);
    + if (err)
    + printk(KERN_ERR "PCI(%s): No usable DMA configuration",
    + pci_name(dev));
    + }
    +
    + *flags_out = flags;
    + return err;
    +}
    +
     static int __devinit pci_init(void)
     {
             struct pci_dev *dev = NULL;
    @@ -765,6 +790,7 @@
     EXPORT_SYMBOL(pci_clear_mwi);
     EXPORT_SYMBOL(pci_set_dma_mask);
     EXPORT_SYMBOL(pci_dac_set_dma_mask);
    +EXPORT_SYMBOL(pci_set_dac);
     EXPORT_SYMBOL(pci_set_consistent_dma_mask);
     EXPORT_SYMBOL(pci_assign_resource);
     EXPORT_SYMBOL(pci_find_parent_resource);
    ===== include/linux/pci.h 1.109 vs edited =====
    --- 1.109/include/linux/pci.h Mon Dec 29 16:37:23 2003
    +++ edited/include/linux/pci.h Wed Dec 31 10:54:16 2003
    @@ -340,6 +340,10 @@
     #define PCIIOC_MMAP_IS_MEM (PCIIOC_BASE | 0x02) /* Set mmap state to MEM space. */
     #define PCIIOC_WRITE_COMBINE (PCIIOC_BASE | 0x03) /* Enable/disable write-combining. */
     
    +/* pci_set_dac flags */
    +#define PCI_DAC_EN (1 << 0)
    +#define PCI_DAC_CONS_EN (1 << 1)
    +
     #ifdef __KERNEL__
     
     #include <linux/types.h>
    @@ -653,6 +657,8 @@
     void pci_clear_mwi(struct pci_dev *dev);
     int pci_set_dma_mask(struct pci_dev *dev, u64 mask);
     int pci_dac_set_dma_mask(struct pci_dev *dev, u64 mask);
    +int pci_set_dac(struct pci_dev *dev, u32 *flags);
    +
     int pci_set_consistent_dma_mask(struct pci_dev *dev, u64 mask);
     int pci_assign_resource(struct pci_dev *dev, int i);
     
    @@ -759,6 +765,8 @@
     static inline int pci_module_init(struct pci_driver *drv) { return -ENODEV; }
     static inline int pci_set_dma_mask(struct pci_dev *dev, u64 mask) { return -EIO; }
     static inline int pci_dac_set_dma_mask(struct pci_dev *dev, u64 mask) { return -EIO; }
    +static inline int pci_set_dac(struct pci_dev *dev, u32 *flags) { return -EIO; }
    +
     static inline int pci_assign_resource(struct pci_dev *dev, int i) { return -EBUSY;}
     static inline int pci_register_driver(struct pci_driver *drv) { return 0;}
     static inline void pci_unregister_driver(struct pci_driver *drv) { }

    -
    To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
    the body of a message to majordomo@vger.kernel.org
    More majordomo info at http://vger.kernel.org/majordomo-info.html
    Please read the FAQ at http://www.tux.org/lkml/


  • Next message: Ben Collins: "Re: 2.6.1-rc1-mm1 - ieee1394 broken again?"

    Relevant Pages

    • Re: dev->release = (void (*)(struct device *))kfree;
      ... will still be unregistered (removed from the various lists) but the ... releasecallback won't be called until the last user. ... send the line "unsubscribe linux-kernel" in ...
      (Linux-Kernel)
    • Re: [RFC] rwsem removal from kobj_map
      ... static int __init genhd_device_init ... static void cdev_default_release ... send the line "unsubscribe linux-kernel" in ...
      (Linux-Kernel)
    • Re: [PATCH 9/8] lib/sort: turn off self-test
      ... +int cmpint(const void *a, const void *b) ... +static int sort_test ... send the line "unsubscribe linux-kernel" in ...
      (Linux-Kernel)
    • [PATCH] w1: Added DS2433 driver.
      ... * it under the smems of the GNU General Public License as published by ... * the Free Software Foundation; ... +static int __init w1_f23_init ... send the line "unsubscribe linux-kernel" in ...
      (Linux-Kernel)
    • Re: modprobe + request_module() deadlock
      ... calls request_moduleonce the depending module went to LIVE state. ... +static int pending_call(struct notifier_block *self, unsigned long state, ... +static struct notifier_block pending_notifier = { ... send the line "unsubscribe linux-kernel" in ...
      (Linux-Kernel)