According to the HyperTransport spec, 'En' indicate if the MSI Mapping is active. So it should be set when enable the MSI.
The patch base on kernel 2.6.24-rc3 Signed-off-by: Andy Currid <[EMAIL PROTECTED]> Signed-off-by: Peer Chen <[EMAIL PROTECTED]> --- --- linux-2.6.24-rc3/drivers/pci/msi.c.orig 2007-11-23 17:28:45.000000000 -0500 +++ linux-2.6.24-rc3/drivers/pci/msi.c 2007-11-23 17:50:59.000000000 -0500 @@ -20,6 +20,8 @@ #include <asm/errno.h> #include <asm/io.h> +#include <asm/k8.h> + #include "pci.h" #include "msi.h" @@ -290,6 +292,99 @@ void pci_restore_msi_state(struct pci_de } #endif /* CONFIG_PM */ +/* + * pci_enable_msi_ht_cap - Set the HT MSI mapping capability En bit of + * a device. + * + * @dev: pointer to the pci_dev data structure of MSI device function + */ + +static int pci_enable_msi_ht_cap(struct pci_dev *dev) +{ + int pos; + u8 flags; + + if ((pos = pci_find_ht_capability(dev, HT_CAPTYPE_MSI_MAPPING)) != 0) + { + pci_read_config_byte(dev, pos + HT_MSI_FLAGS, &flags); + pci_write_config_byte(dev, pos + HT_MSI_FLAGS, + flags | HT_MSI_FLAGS_ENABLE); + + printk(KERN_INFO "PCI: %s: enabled HT MSI mapping\n", pci_name(dev)); + } + + return pos; +} + +/** + * pci_check_msi_ht_cap - check for and enable the MSI mapping capability En bit + * of devices or upstream bridge on HT-base system. + * @dev: pointer to the pci_dev data structure of MSI device function + * + * Search if device support ht MSI mapping capability on HT-base + * platform, if yes, enable the En bit. If device can't support MSI mapping, + * search the the upstream bridge for that capability, enable En bit find it, + * otherwise disable the MSI function if device and upstream bridge can't + * support MSI mapping capability. + **/ + +static int pci_check_msi_ht_cap(struct pci_dev *dev) +{ + struct pci_dev *bridge_dev; + + if (num_k8_northbridges != 0) { /* If the system is the HT-base */ + + /* Check for upstream NVIDIA host bridges */ + + if (((bridge_dev = pci_find_slot(0, 0)) != NULL) && + (bridge_dev->vendor == PCI_VENDOR_ID_NVIDIA)) { + switch (bridge_dev->device) { + case PCI_DEVICE_ID_NVIDIA_NFORCE_C51_MEMC0: + case PCI_DEVICE_ID_NVIDIA_NFORCE_C51_MEMC1: + case PCI_DEVICE_ID_NVIDIA_NFORCE_C51_MEMC2: + case PCI_DEVICE_ID_NVIDIA_NFORCE_C51_MEMC3: + case PCI_DEVICE_ID_NVIDIA_NFORCE_C51_MEMC4: + case PCI_DEVICE_ID_NVIDIA_NFORCE_C51_MEMC5: + case PCI_DEVICE_ID_NVIDIA_NFORCE_C51_MEMC6: + case PCI_DEVICE_ID_NVIDIA_NFORCE_C51_MEMC7: + case PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_MEMC: + + pci_enable_msi_ht_cap(bridge_dev); + + bridge_dev = NULL; + while ((bridge_dev = pci_get_device(PCI_VENDOR_ID_NVIDIA, + PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_MEMC, bridge_dev)) + != NULL) { + pci_enable_msi_ht_cap(bridge_dev); + } + + break; + + default: + break; + } + } + + + if (pci_enable_msi_ht_cap(dev) != 0) { + return 0; + } else { + /* Get upstream bridge device handle */ + + bridge_dev = dev->bus->self; + while(bridge_dev != 0) { + if (pci_enable_msi_ht_cap(bridge_dev) != 0) { + return 0; + } else + bridge_dev = bridge_dev->bus->self; + } + + return 1; + } + } + return 0; +} + /** * msi_capability_init - configure device's MSI capability structure * @dev: pointer to the pci_dev data structure of MSI device function @@ -510,6 +605,10 @@ int pci_enable_msi(struct pci_dev* dev) status = pci_msi_check_device(dev, 1, PCI_CAP_ID_MSI); if (status) return status; + + status = pci_check_msi_ht_cap(dev); + if(status) + return status; WARN_ON(!!dev->msi_enabled); @@ -606,6 +705,10 @@ int pci_enable_msix(struct pci_dev* dev, if (status) return status; + status = pci_check_msi_ht_cap(dev); + if(status) + return status; + pos = pci_find_capability(dev, PCI_CAP_ID_MSIX); pci_read_config_word(dev, msi_control_reg(pos), &control); nr_entries = multi_msix_capable(control); - - To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to [EMAIL PROTECTED] More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/