Skip to content

Commit

Permalink
Merge master.kernel.org:/pub/scm/linux/kernel/git/gregkh/pci-2.6
Browse files Browse the repository at this point in the history
* master.kernel.org:/pub/scm/linux/kernel/git/gregkh/pci-2.6: (27 commits)
  [PATCH] PCI: nVidia quirk to make AER PCI-E extended capability visible
  [PATCH] PCI: fix issues with extended conf space when MMCONFIG disabled because of e820
  [PATCH] PCI: Bus Parity Status sysfs interface
  [PATCH] PCI: fix memory leak in MMCONFIG error path
  [PATCH] PCI: fix error with pci_get_device() call in the mpc85xx driver
  [PATCH] PCI: MSI-K8T-Neo2-Fir: run only where needed
  [PATCH] PCI: fix race with pci_walk_bus and pci_destroy_dev
  [PATCH] PCI: clean up pci documentation to be more specific
  [PATCH] PCI: remove unneeded msi code
  [PATCH] PCI: don't move ioapics below PCI bridge
  [PATCH] PCI: cleanup unused variable about msi driver
  [PATCH] PCI: disable msi mode in pci_disable_device
  [PATCH] PCI: Allow MSI to work on kexec kernel
  [PATCH] PCI: AMD 8131 MSI quirk called too late, bus_flags not inherited ?
  [PATCH] PCI: Move various PCI IDs to header file
  [PATCH] PCI Bus Parity Status-broken hardware attribute, EDAC foundation
  [PATCH] PCI: i386/x86_84: disable PCI resource decode on device disable
  [PATCH] PCI ACPI: Rename the functions to avoid multiple instances.
  [PATCH] PCI: don't enable device if already enabled
  [PATCH] PCI: Add a "enable" sysfs attribute to the pci devices to allow userspace (Xorg) to enable devices without doing foul direct access
  ...
  • Loading branch information
Linus Torvalds committed Jun 22, 2006
2 parents dcc1a66 + cf34a8e commit 6c763eb
Show file tree
Hide file tree
Showing 45 changed files with 1,096 additions and 436 deletions.
14 changes: 11 additions & 3 deletions Documentation/pci.txt
Original file line number Diff line number Diff line change
Expand Up @@ -213,9 +213,17 @@ have been remapped by the kernel.

See Documentation/IO-mapping.txt for how to access device memory.

You still need to call request_region() for I/O regions and
request_mem_region() for memory regions to make sure nobody else is using the
same device.
The device driver needs to call pci_request_region() to make sure
no other device is already using the same resource. The driver is expected
to determine MMIO and IO Port resource availability _before_ calling
pci_enable_device(). Conversely, drivers should call pci_release_region()
_after_ calling pci_disable_device(). The idea is to prevent two devices
colliding on the same address range.

Generic flavors of pci_request_region() are request_mem_region()
(for MMIO ranges) and request_region() (for IO Port ranges).
Use these for address resources that are not described by "normal" PCI
interfaces (e.g. BAR).

All interrupt handlers should be registered with SA_SHIRQ and use the devid
to map IRQs to devices (remember that all PCI interrupts are shared).
Expand Down
2 changes: 2 additions & 0 deletions arch/i386/kernel/acpi/boot.c
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,8 @@ int __init acpi_parse_mcfg(unsigned long phys_addr, unsigned long size)
if (mcfg->config[i].base_reserved) {
printk(KERN_ERR PREFIX
"MMCONFIG not in low 4GB of memory\n");
kfree(pci_mmcfg_config);
pci_mmcfg_config_num = 0;
return -ENODEV;
}
}
Expand Down
1 change: 1 addition & 0 deletions arch/i386/pci/common.c
Original file line number Diff line number Diff line change
Expand Up @@ -288,6 +288,7 @@ int pcibios_enable_device(struct pci_dev *dev, int mask)

void pcibios_disable_device (struct pci_dev *dev)
{
pcibios_disable_resources(dev);
if (pcibios_disable_irq)
pcibios_disable_irq(dev);
}
9 changes: 9 additions & 0 deletions arch/i386/pci/i386.c
Original file line number Diff line number Diff line change
Expand Up @@ -242,6 +242,15 @@ int pcibios_enable_resources(struct pci_dev *dev, int mask)
return 0;
}

void pcibios_disable_resources(struct pci_dev *dev)
{
u16 cmd;

pci_read_config_word(dev, PCI_COMMAND, &cmd);
cmd &= ~(PCI_COMMAND_IO | PCI_COMMAND_MEMORY);
pci_write_config_word(dev, PCI_COMMAND, cmd);
}

/*
* If we set up a device for bus mastering, we need to check the latency
* timer as certain crappy BIOSes forget to set it properly.
Expand Down
9 changes: 6 additions & 3 deletions arch/i386/pci/mmconfig.c
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,9 @@
#include <asm/e820.h>
#include "pci.h"

#define MMCONFIG_APER_SIZE (256*1024*1024)
/* aperture is up to 256MB but BIOS may reserve less */
#define MMCONFIG_APER_MIN (2 * 1024*1024)
#define MMCONFIG_APER_MAX (256 * 1024*1024)

/* Assume systems with more busses have correct MCFG */
#define MAX_CHECK_BUS 16
Expand Down Expand Up @@ -197,9 +199,10 @@ void __init pci_mmcfg_init(void)
return;

if (!e820_all_mapped(pci_mmcfg_config[0].base_address,
pci_mmcfg_config[0].base_address + MMCONFIG_APER_SIZE,
pci_mmcfg_config[0].base_address + MMCONFIG_APER_MIN,
E820_RESERVED)) {
printk(KERN_ERR "PCI: BIOS Bug: MCFG area is not E820-reserved\n");
printk(KERN_ERR "PCI: BIOS Bug: MCFG area at %x is not E820-reserved\n",
pci_mmcfg_config[0].base_address);
printk(KERN_ERR "PCI: Not using MMCONFIG.\n");
return;
}
Expand Down
1 change: 1 addition & 0 deletions arch/i386/pci/pci.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ extern unsigned int pcibios_max_latency;

void pcibios_resource_survey(void);
int pcibios_enable_resources(struct pci_dev *, int);
void pcibios_disable_resources(struct pci_dev *);

/* pci-pc.c */

Expand Down
19 changes: 18 additions & 1 deletion arch/ia64/kernel/irq_ia64.c
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,10 @@

#define IRQ_DEBUG 0

/* These can be overridden in platform_irq_init */
int ia64_first_device_vector = IA64_DEF_FIRST_DEVICE_VECTOR;
int ia64_last_device_vector = IA64_DEF_LAST_DEVICE_VECTOR;

/* default base addr of IPI table */
void __iomem *ipi_base_addr = ((void __iomem *)
(__IA64_UNCACHED_OFFSET | IA64_IPI_DEFAULT_BASE_ADDR));
Expand All @@ -60,7 +64,7 @@ __u8 isa_irq_to_vector_map[16] = {
};
EXPORT_SYMBOL(isa_irq_to_vector_map);

static unsigned long ia64_vector_mask[BITS_TO_LONGS(IA64_NUM_DEVICE_VECTORS)];
static unsigned long ia64_vector_mask[BITS_TO_LONGS(IA64_MAX_DEVICE_VECTORS)];

int
assign_irq_vector (int irq)
Expand Down Expand Up @@ -89,6 +93,19 @@ free_irq_vector (int vector)
printk(KERN_WARNING "%s: double free!\n", __FUNCTION__);
}

int
reserve_irq_vector (int vector)
{
int pos;

if (vector < IA64_FIRST_DEVICE_VECTOR ||
vector > IA64_LAST_DEVICE_VECTOR)
return -EINVAL;

pos = vector - IA64_FIRST_DEVICE_VECTOR;
return test_and_set_bit(pos, ia64_vector_mask);
}

#ifdef CONFIG_SMP
# define IS_RESCHEDULE(vec) (vec == IA64_IPI_RESCHEDULE)
#else
Expand Down
9 changes: 1 addition & 8 deletions arch/ia64/sn/kernel/io_init.c
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ static int max_pcibus_number = 255; /* Default highest pci bus number */
*/

static dma_addr_t
sn_default_pci_map(struct pci_dev *pdev, unsigned long paddr, size_t size)
sn_default_pci_map(struct pci_dev *pdev, unsigned long paddr, size_t size, int type)
{
return 0;
}
Expand Down Expand Up @@ -457,13 +457,6 @@ void sn_pci_fixup_slot(struct pci_dev *dev)
pcidev_info->pdi_sn_irq_info = NULL;
kfree(sn_irq_info);
}

/*
* MSI currently not supported on altix. Remove this when
* the MSI abstraction patches are integrated into the kernel
* (sometime after 2.6.16 releases)
*/
dev->no_msi = 1;
}

/*
Expand Down
142 changes: 84 additions & 58 deletions arch/ia64/sn/kernel/irq.c
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,11 @@ static void unregister_intr_pda(struct sn_irq_info *sn_irq_info);

int sn_force_interrupt_flag = 1;
extern int sn_ioif_inited;
static struct list_head **sn_irq_lh;
struct list_head **sn_irq_lh;
static spinlock_t sn_irq_info_lock = SPIN_LOCK_UNLOCKED; /* non-IRQ lock */

static inline u64 sn_intr_alloc(nasid_t local_nasid, int local_widget,
u64 sn_irq_info,
u64 sn_intr_alloc(nasid_t local_nasid, int local_widget,
struct sn_irq_info *sn_irq_info,
int req_irq, nasid_t req_nasid,
int req_slice)
{
Expand All @@ -40,12 +40,13 @@ static inline u64 sn_intr_alloc(nasid_t local_nasid, int local_widget,

SAL_CALL_NOLOCK(ret_stuff, (u64) SN_SAL_IOIF_INTERRUPT,
(u64) SAL_INTR_ALLOC, (u64) local_nasid,
(u64) local_widget, (u64) sn_irq_info, (u64) req_irq,
(u64) local_widget, __pa(sn_irq_info), (u64) req_irq,
(u64) req_nasid, (u64) req_slice);

return ret_stuff.status;
}

static inline void sn_intr_free(nasid_t local_nasid, int local_widget,
void sn_intr_free(nasid_t local_nasid, int local_widget,
struct sn_irq_info *sn_irq_info)
{
struct ia64_sal_retval ret_stuff;
Expand Down Expand Up @@ -112,73 +113,91 @@ static void sn_end_irq(unsigned int irq)

static void sn_irq_info_free(struct rcu_head *head);

static void sn_set_affinity_irq(unsigned int irq, cpumask_t mask)
struct sn_irq_info *sn_retarget_vector(struct sn_irq_info *sn_irq_info,
nasid_t nasid, int slice)
{
struct sn_irq_info *sn_irq_info, *sn_irq_info_safe;
int cpuid, cpuphys;
int vector;
int cpuphys;
int64_t bridge;
int local_widget, status;
nasid_t local_nasid;
struct sn_irq_info *new_irq_info;
struct sn_pcibus_provider *pci_provider;

cpuid = first_cpu(mask);
cpuphys = cpu_physical_id(cpuid);
new_irq_info = kmalloc(sizeof(struct sn_irq_info), GFP_ATOMIC);
if (new_irq_info == NULL)
return NULL;

list_for_each_entry_safe(sn_irq_info, sn_irq_info_safe,
sn_irq_lh[irq], list) {
u64 bridge;
int local_widget, status;
nasid_t local_nasid;
struct sn_irq_info *new_irq_info;
struct sn_pcibus_provider *pci_provider;

new_irq_info = kmalloc(sizeof(struct sn_irq_info), GFP_ATOMIC);
if (new_irq_info == NULL)
break;
memcpy(new_irq_info, sn_irq_info, sizeof(struct sn_irq_info));

bridge = (u64) new_irq_info->irq_bridge;
if (!bridge) {
kfree(new_irq_info);
break; /* irq is not a device interrupt */
}
memcpy(new_irq_info, sn_irq_info, sizeof(struct sn_irq_info));

bridge = (u64) new_irq_info->irq_bridge;
if (!bridge) {
kfree(new_irq_info);
return NULL; /* irq is not a device interrupt */
}

local_nasid = NASID_GET(bridge);
local_nasid = NASID_GET(bridge);

if (local_nasid & 1)
local_widget = TIO_SWIN_WIDGETNUM(bridge);
else
local_widget = SWIN_WIDGETNUM(bridge);
if (local_nasid & 1)
local_widget = TIO_SWIN_WIDGETNUM(bridge);
else
local_widget = SWIN_WIDGETNUM(bridge);

/* Free the old PROM new_irq_info structure */
sn_intr_free(local_nasid, local_widget, new_irq_info);
/* Update kernels new_irq_info with new target info */
unregister_intr_pda(new_irq_info);
vector = sn_irq_info->irq_irq;
/* Free the old PROM new_irq_info structure */
sn_intr_free(local_nasid, local_widget, new_irq_info);
/* Update kernels new_irq_info with new target info */
unregister_intr_pda(new_irq_info);

/* allocate a new PROM new_irq_info struct */
status = sn_intr_alloc(local_nasid, local_widget,
__pa(new_irq_info), irq,
cpuid_to_nasid(cpuid),
cpuid_to_slice(cpuid));
/* allocate a new PROM new_irq_info struct */
status = sn_intr_alloc(local_nasid, local_widget,
new_irq_info, vector,
nasid, slice);

/* SAL call failed */
if (status) {
kfree(new_irq_info);
break;
}
/* SAL call failed */
if (status) {
kfree(new_irq_info);
return NULL;
}

new_irq_info->irq_cpuid = cpuid;
register_intr_pda(new_irq_info);
cpuphys = nasid_slice_to_cpuid(nasid, slice);
new_irq_info->irq_cpuid = cpuphys;
register_intr_pda(new_irq_info);

pci_provider = sn_pci_provider[new_irq_info->irq_bridge_type];
if (pci_provider && pci_provider->target_interrupt)
(pci_provider->target_interrupt)(new_irq_info);
pci_provider = sn_pci_provider[new_irq_info->irq_bridge_type];

spin_lock(&sn_irq_info_lock);
list_replace_rcu(&sn_irq_info->list, &new_irq_info->list);
spin_unlock(&sn_irq_info_lock);
call_rcu(&sn_irq_info->rcu, sn_irq_info_free);
/*
* If this represents a line interrupt, target it. If it's
* an msi (irq_int_bit < 0), it's already targeted.
*/
if (new_irq_info->irq_int_bit >= 0 &&
pci_provider && pci_provider->target_interrupt)
(pci_provider->target_interrupt)(new_irq_info);

spin_lock(&sn_irq_info_lock);
list_replace_rcu(&sn_irq_info->list, &new_irq_info->list);
spin_unlock(&sn_irq_info_lock);
call_rcu(&sn_irq_info->rcu, sn_irq_info_free);

#ifdef CONFIG_SMP
set_irq_affinity_info((irq & 0xff), cpuphys, 0);
set_irq_affinity_info((vector & 0xff), cpuphys, 0);
#endif
}

return new_irq_info;
}

static void sn_set_affinity_irq(unsigned int irq, cpumask_t mask)
{
struct sn_irq_info *sn_irq_info, *sn_irq_info_safe;
nasid_t nasid;
int slice;

nasid = cpuid_to_nasid(first_cpu(mask));
slice = cpuid_to_slice(first_cpu(mask));

list_for_each_entry_safe(sn_irq_info, sn_irq_info_safe,
sn_irq_lh[irq], list)
(void)sn_retarget_vector(sn_irq_info, nasid, slice);
}

struct hw_interrupt_type irq_type_sn = {
Expand All @@ -202,6 +221,9 @@ void sn_irq_init(void)
int i;
irq_desc_t *base_desc = irq_desc;

ia64_first_device_vector = IA64_SN2_FIRST_DEVICE_VECTOR;
ia64_last_device_vector = IA64_SN2_LAST_DEVICE_VECTOR;

for (i = 0; i < NR_IRQS; i++) {
if (base_desc[i].handler == &no_irq_type) {
base_desc[i].handler = &irq_type_sn;
Expand Down Expand Up @@ -285,6 +307,7 @@ void sn_irq_fixup(struct pci_dev *pci_dev, struct sn_irq_info *sn_irq_info)
/* link it into the sn_irq[irq] list */
spin_lock(&sn_irq_info_lock);
list_add_rcu(&sn_irq_info->list, sn_irq_lh[sn_irq_info->irq_irq]);
reserve_irq_vector(sn_irq_info->irq_irq);
spin_unlock(&sn_irq_info_lock);

register_intr_pda(sn_irq_info);
Expand All @@ -310,8 +333,11 @@ void sn_irq_unfixup(struct pci_dev *pci_dev)
spin_lock(&sn_irq_info_lock);
list_del_rcu(&sn_irq_info->list);
spin_unlock(&sn_irq_info_lock);
if (list_empty(sn_irq_lh[sn_irq_info->irq_irq]))
free_irq_vector(sn_irq_info->irq_irq);
call_rcu(&sn_irq_info->rcu, sn_irq_info_free);
pci_dev_put(pci_dev);

}

static inline void
Expand Down
10 changes: 6 additions & 4 deletions arch/ia64/sn/pci/pci_dma.c
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@

#include <linux/module.h>
#include <asm/dma.h>
#include <asm/sn/pcibr_provider.h>
#include <asm/sn/intr.h>
#include <asm/sn/pcibus_provider_defs.h>
#include <asm/sn/pcidev.h>
#include <asm/sn/sn_sal.h>
Expand Down Expand Up @@ -113,7 +113,8 @@ void *sn_dma_alloc_coherent(struct device *dev, size_t size,
* resources.
*/

*dma_handle = provider->dma_map_consistent(pdev, phys_addr, size);
*dma_handle = provider->dma_map_consistent(pdev, phys_addr, size,
SN_DMA_ADDR_PHYS);
if (!*dma_handle) {
printk(KERN_ERR "%s: out of ATEs\n", __FUNCTION__);
free_pages((unsigned long)cpuaddr, get_order(size));
Expand Down Expand Up @@ -176,7 +177,7 @@ dma_addr_t sn_dma_map_single(struct device *dev, void *cpu_addr, size_t size,
BUG_ON(dev->bus != &pci_bus_type);

phys_addr = __pa(cpu_addr);
dma_addr = provider->dma_map(pdev, phys_addr, size);
dma_addr = provider->dma_map(pdev, phys_addr, size, SN_DMA_ADDR_PHYS);
if (!dma_addr) {
printk(KERN_ERR "%s: out of ATEs\n", __FUNCTION__);
return 0;
Expand Down Expand Up @@ -260,7 +261,8 @@ int sn_dma_map_sg(struct device *dev, struct scatterlist *sg, int nhwentries,
for (i = 0; i < nhwentries; i++, sg++) {
phys_addr = SG_ENT_PHYS_ADDRESS(sg);
sg->dma_address = provider->dma_map(pdev,
phys_addr, sg->length);
phys_addr, sg->length,
SN_DMA_ADDR_PHYS);

if (!sg->dma_address) {
printk(KERN_ERR "%s: out of ATEs\n", __FUNCTION__);
Expand Down
Loading

0 comments on commit 6c763eb

Please sign in to comment.