Commit 82670e1f authored by Linus Torvalds's avatar Linus Torvalds

Merge bk://linuxusb.bkbits.net/pci_hp-2.5

into home.transmeta.com:/home/torvalds/v2.5/linux
parents 42003664 d53e21af
......@@ -2218,6 +2218,15 @@ S: 30 White Tail Lane
S: Lafayette, Indiana 47905
S: USA
N: Scott Murray
E: scottm@somanetworks.com
E: scott@spiteful.org
D: OPL3-SA2, OPL3-SA3 sound driver
D: CompactPCI hotplug core
D: Ziatech ZT5550 and generic CompactPCI hotplug drivers
S: Toronto, Ontario
S: Canada
N: Trond Myklebust
E: trond.myklebust@fys.uio.no
D: current NFS client hacker.
......
......@@ -317,6 +317,27 @@ L: codalist@coda.cs.cmu.edu
W: http://www.coda.cs.cmu.edu/
S: Maintained
COMPACTPCI HOTPLUG CORE
P: Scott Murray
M: scottm@somanetworks.com
M: scott@spiteful.org
L: pcihpd-discuss@lists.sourceforge.net
S: Supported
COMPACTPCI HOTPLUG ZIATECH ZT5550 DRIVER
P: Scott Murray
M: scottm@somanetworks.com
M: scott@spiteful.org
L: pcihpd-discuss@lists.sourceforge.net
S: Supported
COMPACTPCI HOTPLUG GENERIC DRIVER
P: Scott Murray
M: scottm@somanetworks.com
M: scott@spiteful.org
L: pcihpd-discuss@lists.sourceforge.net
S: Supported
COMPAQ FIBRE CHANNEL 64-bit/66MHz PCI non-intelligent HBA
P: Amy Vanzant-Hodge
M: Amy Vanzant-Hodge (fibrechannel@compaq.com)
......
......@@ -340,7 +340,7 @@ common_swizzle(struct pci_dev *dev, u8 *pinp)
return PCI_SLOT(dev->devfn);
}
void __init
void __devinit
pcibios_fixup_pbus_ranges(struct pci_bus * bus,
struct pbus_set_ranges_data * ranges)
{
......
......@@ -90,6 +90,11 @@ static void __devinit pcibios_fixup_ghosts(struct pci_bus *b)
}
}
void __devinit
pcibios_fixup_pbus_ranges (struct pci_bus *bus, struct pbus_set_ranges_data *ranges)
{
}
/*
* Called after each bus is probed, but before its children
* are examined.
......
......@@ -138,7 +138,7 @@ static void __devinit pci_fixup_piix4_acpi(struct pci_dev *d)
#define VIA_8363_KL133_REVISION_ID 0x81
#define VIA_8363_KM133_REVISION_ID 0x84
static void __init pci_fixup_via_northbridge_bug(struct pci_dev *d)
static void __devinit pci_fixup_via_northbridge_bug(struct pci_dev *d)
{
u8 v;
u8 revision;
......@@ -180,7 +180,7 @@ static void __init pci_fixup_via_northbridge_bug(struct pci_dev *d)
* system to PCI bus no matter what are their window settings, so they are
* "transparent" (or subtractive decoding) from programmers point of view.
*/
static void __init pci_fixup_transparent_bridge(struct pci_dev *dev)
static void __devinit pci_fixup_transparent_bridge(struct pci_dev *dev)
{
if ((dev->class >> 8) == PCI_CLASS_BRIDGE_PCI &&
(dev->device & 0xff00) == 0x2400)
......
......@@ -297,8 +297,8 @@ void __init pcibios_update_irq(struct pci_dev *dev, int irq)
pci_write_config_byte(dev, PCI_INTERRUPT_LINE, irq);
}
void __init pcibios_fixup_pbus_ranges(struct pci_bus *bus,
struct pbus_set_ranges_data *ranges)
void __devinit pcibios_fixup_pbus_ranges(struct pci_bus *bus,
struct pbus_set_ranges_data *ranges)
{
}
......
......@@ -341,8 +341,8 @@ void __init pcibios_update_irq(struct pci_dev *dev, int irq)
pci_write_config_byte(dev, PCI_INTERRUPT_LINE, irq);
}
void __init pcibios_fixup_pbus_ranges(struct pci_bus *bus,
struct pbus_set_ranges_data *ranges)
void __devinit pcibios_fixup_pbus_ranges(struct pci_bus *bus,
struct pbus_set_ranges_data *ranges)
{
/*
* our caller figure out range by going through the dev structures.
......
......@@ -234,7 +234,7 @@ pcibios_fixup_bus(struct pci_bus *b)
pci_fixup_irqs(pci_swizzle, pci_map_irq);
}
void __init
void __devinit
pcibios_fixup_pbus_ranges(struct pci_bus * bus,
struct pbus_set_ranges_data * ranges)
{
......
......@@ -349,8 +349,8 @@ void __init pcibios_fixup_bus (struct pci_bus *b)
}
/* XXX anybody know what this is supposed to do? */
void __init pcibios_fixup_pbus_ranges(struct pci_bus * bus,
struct pbus_set_ranges_data * ranges)
void __devinit pcibios_fixup_pbus_ranges(struct pci_bus * bus,
struct pbus_set_ranges_data * ranges)
{
}
......
......@@ -345,7 +345,7 @@ pcibios_link_hba_resources( struct resource *hba_res, struct resource *r)
/*
** called by drivers/pci/setup-res.c:pci_setup_bridge().
*/
void pcibios_fixup_pbus_ranges(
void __devinit pcibios_fixup_pbus_ranges(
struct pci_bus *bus,
struct pbus_set_ranges_data *ranges
)
......
......@@ -1107,7 +1107,7 @@ common_swizzle(struct pci_dev *dev, unsigned char *pinp)
return PCI_SLOT(dev->devfn);
}
void __init
void __devinit
pcibios_fixup_pbus_ranges(struct pci_bus * bus, struct pbus_set_ranges_data * ranges)
{
}
......
......@@ -121,8 +121,8 @@ static void fixup_windbond_82c105(struct pci_dev* dev)
}
void pcibios_fixup_pbus_ranges(struct pci_bus *pbus,
struct pbus_set_ranges_data *pranges)
void __devinit pcibios_fixup_pbus_ranges(struct pci_bus *pbus,
struct pbus_set_ranges_data *pranges)
{
}
......
......@@ -113,7 +113,7 @@ void pci_free_consistent(struct pci_dev *hwdev, size_t size,
}
void __init pcibios_fixup_pbus_ranges(struct pci_bus *bus, struct pbus_set_ranges_data *ranges)
void __devinit pcibios_fixup_pbus_ranges(struct pci_bus *bus, struct pbus_set_ranges_data *ranges)
{
}
......
......@@ -250,8 +250,8 @@ struct pci_fixup pcibios_fixups[] = {
{ 0 }
};
void __init pcibios_fixup_pbus_ranges(struct pci_bus *b,
struct pbus_set_ranges_data *range)
void __devinit pcibios_fixup_pbus_ranges(struct pci_bus *b,
struct pbus_set_ranges_data *range)
{
/* No fixups needed */
}
......
......@@ -380,7 +380,7 @@ static int __init map_harp_irq(struct pci_dev *dev, u8 slot, u8 pin)
}
void __init
void __devinit
pcibios_fixup_pbus_ranges(struct pci_bus *bus,
struct pbus_set_ranges_data *ranges)
{
......
......@@ -479,8 +479,8 @@ void pcibios_update_irq(struct pci_dev *pdev, int irq)
{
}
void pcibios_fixup_pbus_ranges(struct pci_bus *pbus,
struct pbus_set_ranges_data *pranges)
void __devinit pcibios_fixup_pbus_ranges(struct pci_bus *pbus,
struct pbus_set_ranges_data *pranges)
{
}
......
......@@ -73,5 +73,48 @@ config HOTPLUG_PCI_ACPI
When in doubt, say N.
config HOTPLUG_PCI_CPCI
tristate "CompactPCI Hotplug driver"
depends on HOTPLUG_PCI
help
Say Y here if you have a CompactPCI system card with CompactPCI
hotswap support per the PICMG 2.1 specification.
This code is also available as a module ( = code which can be
inserted in and removed from the running kernel whenever you want).
The module will be called cpci_hotplug.o. If you want to compile it
as a module, say M here and read <file:Documentation/modules.txt>.
When in doubt, say N.
config HOTPLUG_PCI_CPCI_ZT5550
tristate "Ziatech ZT5550 CompactPCI Hotplug driver"
depends on HOTPLUG_PCI_CPCI && X86
help
Say Y here if you have an Performance Technologies (formerly Intel,
formerly just Ziatech) Ziatech ZT5550 CompactPCI system card.
This code is also available as a module ( = code which can be
inserted in and removed from the running kernel whenever you want).
The module will be called cpcihp_zt5550.o. If you want to compile it
as a module, say M here and read <file:Documentation/modules.txt>.
When in doubt, say N.
config HOTPLUG_PCI_CPCI_GENERIC
tristate "Generic port I/O CompactPCI Hotplug driver"
depends on HOTPLUG_PCI_CPCI && X86
help
Say Y here if you have a CompactPCI system card that exposes the #ENUM
hotswap signal as a bit in a system register that can be read through
standard port I/O.
This code is also available as a module ( = code which can be
inserted in and removed from the running kernel whenever you want).
The module will be called cpcihp_generic.o. If you want to compile it
as a module, say M here and read <file:Documentation/modules.txt>.
When in doubt, say N.
endmenu
......@@ -2,12 +2,15 @@
# Makefile for the Linux kernel pci hotplug controller drivers.
#
export-objs := pci_hotplug_core.o pci_hotplug_util.o
export-objs := pci_hotplug_core.o pci_hotplug_util.o cpci_hotplug_core.o
obj-$(CONFIG_HOTPLUG_PCI) += pci_hotplug.o
obj-$(CONFIG_HOTPLUG_PCI_COMPAQ) += cpqphp.o
obj-$(CONFIG_HOTPLUG_PCI_IBM) += ibmphp.o
obj-$(CONFIG_HOTPLUG_PCI_ACPI) += acpiphp.o
obj-$(CONFIG_HOTPLUG_PCI_CPCI) += cpci_hotplug.o
obj-$(CONFIG_HOTPLUG_PCI_CPCI_ZT5550) += cpcihp_zt5550.o
obj-$(CONFIG_HOTPLUG_PCI_CPCI_GENERIC) += cpcihp_generic.o
pci_hotplug-objs := pci_hotplug_core.o \
pci_hotplug_util.o
......@@ -28,6 +31,9 @@ acpiphp-objs := acpiphp_core.o \
acpiphp_pci.o \
acpiphp_res.o
cpci_hotplug-objs := cpci_hotplug_core.o \
cpci_hotplug_pci.o
ifdef CONFIG_HOTPLUG_PCI_ACPI
EXTRA_CFLAGS += -D_LINUX -I$(TOPDIR)/drivers/acpi
ifdef CONFIG_ACPI_DEBUG
......
......@@ -41,12 +41,12 @@
#define dbg(format, arg...) \
do { \
if (acpiphp_debug) \
printk (KERN_DEBUG "%s: " format "\n", \
printk(KERN_DEBUG "%s: " format, \
MY_NAME , ## arg); \
} while (0)
#define err(format, arg...) printk (KERN_ERR "%s: " format "\n", MY_NAME , ## arg)
#define info(format, arg...) printk (KERN_INFO "%s: " format "\n", MY_NAME , ## arg)
#define warn(format, arg...) printk (KERN_WARNING "%s: " format "\n", MY_NAME , ## arg)
#define err(format, arg...) printk(KERN_ERR "%s: " format, MY_NAME , ## arg)
#define info(format, arg...) printk(KERN_INFO "%s: " format, MY_NAME , ## arg)
#define warn(format, arg...) printk(KERN_WARNING "%s: " format, MY_NAME , ## arg)
#define SLOT_MAGIC 0x67267322
/* name size which is used for entries in pcihpfs */
......
......@@ -50,6 +50,7 @@ static LIST_HEAD(slot_list);
#define MY_NAME THIS_MODULE->name
#endif
static int debug;
int acpiphp_debug;
/* local variables */
......@@ -62,8 +63,8 @@ static int num_slots;
MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_LICENSE("GPL");
MODULE_PARM(acpiphp_debug, "i");
MODULE_PARM_DESC(acpiphp_debug, "Debugging mode enabled or not");
MODULE_PARM(debug, "i");
MODULE_PARM_DESC(debug, "Debugging mode enabled or not");
static int enable_slot (struct hotplug_slot *slot);
static int disable_slot (struct hotplug_slot *slot);
......@@ -95,15 +96,15 @@ static struct hotplug_slot_ops acpi_hotplug_slot_ops = {
static inline int slot_paranoia_check (struct slot *slot, const char *function)
{
if (!slot) {
dbg("%s - slot == NULL", function);
dbg("%s - slot == NULL\n", function);
return -1;
}
if (slot->magic != SLOT_MAGIC) {
dbg("%s - bad magic number for slot", function);
dbg("%s - bad magic number for slot\n", function);
return -1;
}
if (!slot->hotplug_slot) {
dbg("%s - slot->hotplug_slot == NULL!", function);
dbg("%s - slot->hotplug_slot == NULL!\n", function);
return -1;
}
return 0;
......@@ -111,16 +112,16 @@ static inline int slot_paranoia_check (struct slot *slot, const char *function)
static inline struct slot *get_slot (struct hotplug_slot *hotplug_slot, const char *function)
{
{
struct slot *slot;
if (!hotplug_slot) {
dbg("%s - hotplug_slot == NULL", function);
dbg("%s - hotplug_slot == NULL\n", function);
return NULL;
}
slot = (struct slot *)hotplug_slot->private;
if (slot_paranoia_check (slot, function))
if (slot_paranoia_check(slot, function))
return NULL;
return slot;
}
......@@ -135,16 +136,16 @@ static inline struct slot *get_slot (struct hotplug_slot *hotplug_slot, const ch
*/
static int enable_slot (struct hotplug_slot *hotplug_slot)
{
struct slot *slot = get_slot (hotplug_slot, __FUNCTION__);
struct slot *slot = get_slot(hotplug_slot, __FUNCTION__);
int retval = 0;
if (slot == NULL)
return -ENODEV;
dbg ("%s - physical_slot = %s", __FUNCTION__, hotplug_slot->name);
dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
/* enable the specified slot */
retval = acpiphp_enable_slot (slot->acpi_slot);
retval = acpiphp_enable_slot(slot->acpi_slot);
return retval;
}
......@@ -159,16 +160,16 @@ static int enable_slot (struct hotplug_slot *hotplug_slot)
*/
static int disable_slot (struct hotplug_slot *hotplug_slot)
{
struct slot *slot = get_slot (hotplug_slot, __FUNCTION__);
struct slot *slot = get_slot(hotplug_slot, __FUNCTION__);
int retval = 0;
if (slot == NULL)
return -ENODEV;
dbg ("%s - physical_slot = %s", __FUNCTION__, hotplug_slot->name);
dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
/* disable the specified slot */
retval = acpiphp_disable_slot (slot->acpi_slot);
retval = acpiphp_disable_slot(slot->acpi_slot);
return retval;
}
......@@ -185,8 +186,8 @@ static int disable_slot (struct hotplug_slot *hotplug_slot)
static int set_attention_status (struct hotplug_slot *hotplug_slot, u8 status)
{
int retval = 0;
dbg ("%s - physical_slot = %s", __FUNCTION__, hotplug_slot->name);
dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
switch (status) {
case 0:
......@@ -213,15 +214,15 @@ static int set_attention_status (struct hotplug_slot *hotplug_slot, u8 status)
*/
static int hardware_test (struct hotplug_slot *hotplug_slot, u32 value)
{
struct slot *slot = get_slot (hotplug_slot, __FUNCTION__);
struct slot *slot = get_slot(hotplug_slot, __FUNCTION__);
int retval = 0;
if (slot == NULL)
return -ENODEV;
dbg ("%s - physical_slot = %s", __FUNCTION__, hotplug_slot->name);
err ("No hardware tests are defined for this driver");
dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
err("No hardware tests are defined for this driver\n");
retval = -ENODEV;
return retval;
......@@ -239,15 +240,15 @@ static int hardware_test (struct hotplug_slot *hotplug_slot, u32 value)
*/
static int get_power_status (struct hotplug_slot *hotplug_slot, u8 *value)
{
struct slot *slot = get_slot (hotplug_slot, __FUNCTION__);
struct slot *slot = get_slot(hotplug_slot, __FUNCTION__);
int retval = 0;
if (slot == NULL)
return -ENODEV;
dbg("%s - physical_slot = %s", __FUNCTION__, hotplug_slot->name);
*value = acpiphp_get_power_status (slot->acpi_slot);
dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
*value = acpiphp_get_power_status(slot->acpi_slot);
return retval;
}
......@@ -263,8 +264,8 @@ static int get_power_status (struct hotplug_slot *hotplug_slot, u8 *value)
static int get_attention_status (struct hotplug_slot *hotplug_slot, u8 *value)
{
int retval = 0;
dbg("%s - physical_slot = %s", __FUNCTION__, hotplug_slot->name);
dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
*value = hotplug_slot->info->attention_status;
......@@ -283,15 +284,15 @@ static int get_attention_status (struct hotplug_slot *hotplug_slot, u8 *value)
*/
static int get_latch_status (struct hotplug_slot *hotplug_slot, u8 *value)
{
struct slot *slot = get_slot (hotplug_slot, __FUNCTION__);
struct slot *slot = get_slot(hotplug_slot, __FUNCTION__);
int retval = 0;
if (slot == NULL)
return -ENODEV;
dbg("%s - physical_slot = %s", __FUNCTION__, hotplug_slot->name);
*value = acpiphp_get_latch_status (slot->acpi_slot);
dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
*value = acpiphp_get_latch_status(slot->acpi_slot);
return retval;
}
......@@ -308,15 +309,15 @@ static int get_latch_status (struct hotplug_slot *hotplug_slot, u8 *value)
*/
static int get_adapter_status (struct hotplug_slot *hotplug_slot, u8 *value)
{
struct slot *slot = get_slot (hotplug_slot, __FUNCTION__);
struct slot *slot = get_slot(hotplug_slot, __FUNCTION__);
int retval = 0;
if (slot == NULL)
return -ENODEV;
dbg("%s - physical_slot = %s", __FUNCTION__, hotplug_slot->name);
*value = acpiphp_get_adapter_status (slot->acpi_slot);
dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
*value = acpiphp_get_adapter_status(slot->acpi_slot);
return retval;
}
......@@ -325,11 +326,11 @@ static int get_adapter_status (struct hotplug_slot *hotplug_slot, u8 *value)
/* return dummy value because ACPI doesn't provide any method... */
static int get_max_bus_speed (struct hotplug_slot *hotplug_slot, enum pci_bus_speed *value)
{
struct slot *slot = get_slot (hotplug_slot, __FUNCTION__);
struct slot *slot = get_slot(hotplug_slot, __FUNCTION__);
if (slot == NULL)
return -ENODEV;
*value = PCI_SPEED_UNKNOWN;
return 0;
......@@ -339,11 +340,11 @@ static int get_max_bus_speed (struct hotplug_slot *hotplug_slot, enum pci_bus_sp
/* return dummy value because ACPI doesn't provide any method... */
static int get_cur_bus_speed (struct hotplug_slot *hotplug_slot, enum pci_bus_speed *value)
{
struct slot *slot = get_slot (hotplug_slot, __FUNCTION__);
struct slot *slot = get_slot(hotplug_slot, __FUNCTION__);
if (slot == NULL)
return -ENODEV;
*value = PCI_SPEED_UNKNOWN;
return 0;
......@@ -375,10 +376,10 @@ static int init_acpi (void)
*/
static void make_slot_name (struct slot *slot)
{
snprintf (slot->hotplug_slot->name, SLOT_NAME_SIZE, "ACPI%d-%02x:%02x",
slot->acpi_slot->sun,
slot->acpi_slot->bridge->bus,
slot->acpi_slot->device);
snprintf(slot->hotplug_slot->name, SLOT_NAME_SIZE, "ACPI%d-%02x:%02x",
slot->acpi_slot->sun,
slot->acpi_slot->bridge->bus,
slot->acpi_slot->device);
}
/**
......@@ -392,31 +393,31 @@ static int init_slots (void)
int i;
for (i = 0; i < num_slots; ++i) {
slot = kmalloc (sizeof (struct slot), GFP_KERNEL);
slot = kmalloc(sizeof(struct slot), GFP_KERNEL);
if (!slot)
return -ENOMEM;
memset(slot, 0, sizeof(struct slot));
slot->hotplug_slot = kmalloc (sizeof (struct hotplug_slot), GFP_KERNEL);
slot->hotplug_slot = kmalloc(sizeof(struct hotplug_slot), GFP_KERNEL);
if (!slot->hotplug_slot) {
kfree (slot);
kfree(slot);
return -ENOMEM;
}
memset(slot->hotplug_slot, 0, sizeof (struct hotplug_slot));
memset(slot->hotplug_slot, 0, sizeof(struct hotplug_slot));
slot->hotplug_slot->info = kmalloc (sizeof (struct hotplug_slot_info), GFP_KERNEL);
slot->hotplug_slot->info = kmalloc(sizeof(struct hotplug_slot_info), GFP_KERNEL);
if (!slot->hotplug_slot->info) {
kfree (slot->hotplug_slot);
kfree (slot);
kfree(slot->hotplug_slot);
kfree(slot);
return -ENOMEM;
}
memset(slot->hotplug_slot->info, 0, sizeof (struct hotplug_slot_info));
memset(slot->hotplug_slot->info, 0, sizeof(struct hotplug_slot_info));
slot->hotplug_slot->name = kmalloc (SLOT_NAME_SIZE, GFP_KERNEL);
slot->hotplug_slot->name = kmalloc(SLOT_NAME_SIZE, GFP_KERNEL);
if (!slot->hotplug_slot->name) {
kfree (slot->hotplug_slot->info);
kfree (slot->hotplug_slot);
kfree (slot);
kfree(slot->hotplug_slot->info);
kfree(slot->hotplug_slot);
kfree(slot);
return -ENOMEM;
}
......@@ -426,27 +427,27 @@ static int init_slots (void)
slot->hotplug_slot->private = slot;
slot->hotplug_slot->ops = &acpi_hotplug_slot_ops;
slot->acpi_slot = get_slot_from_id (i);
slot->acpi_slot = get_slot_from_id(i);
slot->hotplug_slot->info->power_status = acpiphp_get_power_status(slot->acpi_slot);
slot->hotplug_slot->info->attention_status = acpiphp_get_attention_status(slot->acpi_slot);
slot->hotplug_slot->info->latch_status = acpiphp_get_latch_status(slot->acpi_slot);
slot->hotplug_slot->info->adapter_status = acpiphp_get_adapter_status(slot->acpi_slot);
make_slot_name (slot);
make_slot_name(slot);
retval = pci_hp_register (slot->hotplug_slot);
retval = pci_hp_register(slot->hotplug_slot);
if (retval) {
err ("pci_hp_register failed with error %d", retval);
kfree (slot->hotplug_slot->info);
kfree (slot->hotplug_slot->name);
kfree (slot->hotplug_slot);
kfree (slot);
err("pci_hp_register failed with error %d\n", retval);
kfree(slot->hotplug_slot->info);
kfree(slot->hotplug_slot->name);
kfree(slot->hotplug_slot);
kfree(slot);
return retval;
}
/* add slot to our internal list */
list_add (&slot->slot_list, &slot_list);
info("Slot [%s] registered", slot->hotplug_slot->name);
list_add(&slot->slot_list, &slot_list);
info("Slot [%s] registered\n", slot->hotplug_slot->name);
}
return retval;
......@@ -459,13 +460,13 @@ static void cleanup_slots (void)
struct slot *slot;
list_for_each_safe (tmp, n, &slot_list) {
slot = list_entry (tmp, struct slot, slot_list);
list_del (&slot->slot_list);
pci_hp_deregister (slot->hotplug_slot);
kfree (slot->hotplug_slot->info);
kfree (slot->hotplug_slot->name);
kfree (slot->hotplug_slot);
kfree (slot);
slot = list_entry(tmp, struct slot, slot_list);
list_del(&slot->slot_list);
pci_hp_deregister(slot->hotplug_slot);
kfree(slot->hotplug_slot->info);
kfree(slot->hotplug_slot->name);
kfree(slot->hotplug_slot);
kfree(slot);
}
return;
......@@ -476,7 +477,9 @@ static int __init acpiphp_init(void)
{
int retval;
info (DRIVER_DESC " version: " DRIVER_VERSION);
info(DRIVER_DESC " version: " DRIVER_VERSION "\n");
acpiphp_debug = debug;
/* read all the ACPI info from the system */
retval = init_acpi();
......
......@@ -153,7 +153,7 @@ register_slot (acpi_handle handle, u32 lvl, void *context, void **rv)
for (slot = bridge->slots; slot; slot = slot->next)
if (slot->device == device) {
if (slot->sun != sun)
warn("sibling found, but _SUN doesn't match!");
warn("sibling found, but _SUN doesn't match!\n");
break;
}
......@@ -177,7 +177,7 @@ register_slot (acpi_handle handle, u32 lvl, void *context, void **rv)
bridge->nr_slots++;
dbg("found ACPI PCI Hotplug slot at PCI %02x:%02x Slot:0x%x",
dbg("found ACPI PCI Hotplug slot at PCI %02x:%02x Slot:%d\n",
slot->bridge->bus, slot->device, slot->sun);
}
......@@ -202,7 +202,7 @@ register_slot (acpi_handle handle, u32 lvl, void *context, void **rv)
newfunc);
if (ACPI_FAILURE(status)) {
err("failed to register interrupt notify handler");
err("failed to register interrupt notify handler\n");
return status;
}
......@@ -302,21 +302,21 @@ decode_acpi_resource (acpi_resource *resource, struct acpiphp_bridge *bridge)
switch (resource_type) {
case ACPI_MEMORY_RANGE:
if (cache_attribute == ACPI_PREFETCHABLE_MEMORY) {
dbg("resource type: prefetchable memory 0x%x - 0x%x", (u32)min_address_range, (u32)max_address_range);
dbg("resource type: prefetchable memory 0x%x - 0x%x\n", (u32)min_address_range, (u32)max_address_range);
res = acpiphp_make_resource(min_address_range,
address_length);
if (!res) {
err("out of memory");
err("out of memory\n");
return;
}
res->next = bridge->p_mem_head;
bridge->p_mem_head = res;
} else {
dbg("resource type: memory 0x%x - 0x%x", (u32)min_address_range, (u32)max_address_range);
dbg("resource type: memory 0x%x - 0x%x\n", (u32)min_address_range, (u32)max_address_range);
res = acpiphp_make_resource(min_address_range,
address_length);
if (!res) {
err("out of memory");
err("out of memory\n");
return;
}
res->next = bridge->mem_head;
......@@ -324,22 +324,22 @@ decode_acpi_resource (acpi_resource *resource, struct acpiphp_bridge *bridge)
}
break;
case ACPI_IO_RANGE:
dbg("resource type: io 0x%x - 0x%x", (u32)min_address_range, (u32)max_address_range);
dbg("resource type: io 0x%x - 0x%x\n", (u32)min_address_range, (u32)max_address_range);
res = acpiphp_make_resource(min_address_range,
address_length);
if (!res) {
err("out of memory");
err("out of memory\n");
return;
}
res->next = bridge->io_head;
bridge->io_head = res;
break;
case ACPI_BUS_NUMBER_RANGE:
dbg("resource type: bus number %d - %d", (u32)min_address_range, (u32)max_address_range);
dbg("resource type: bus number %d - %d\n", (u32)min_address_range, (u32)max_address_range);
res = acpiphp_make_resource(min_address_range,
address_length);
if (!res) {
err("out of memory");
err("out of memory\n");
return;
}
res->next = bridge->bus_head;
......@@ -356,10 +356,9 @@ decode_acpi_resource (acpi_resource *resource, struct acpiphp_bridge *bridge)
acpiphp_resource_sort_and_combine(&bridge->mem_head);
acpiphp_resource_sort_and_combine(&bridge->p_mem_head);
acpiphp_resource_sort_and_combine(&bridge->bus_head);
#if 1
info("ACPI _CRS resource:");
dbg("ACPI _CRS resource:\n");
acpiphp_dump_resource(bridge);
#endif
}
......@@ -368,7 +367,7 @@ static struct pci_bus *find_pci_bus(const struct list_head *list, int bus)
{
const struct list_head *l;
list_for_each(l, list) {
list_for_each (l, list) {
struct pci_bus *b = pci_bus_b(l);
if (b->number == bus)
return b;
......@@ -404,7 +403,7 @@ static void decode_hpp(struct acpiphp_bridge *bridge)
status = acpi_evaluate_object(bridge->handle, "_HPP", NULL, &buffer);
if (ACPI_FAILURE(status)) {
dbg("_HPP evaluation failed");
dbg("_HPP evaluation failed\n");
return;
}
......@@ -412,13 +411,13 @@ static void decode_hpp(struct acpiphp_bridge *bridge)
if (!package || package->type != ACPI_TYPE_PACKAGE ||
package->package.count != 4 || !package->package.elements) {
err("invalid _HPP object; ignoring");
err("invalid _HPP object; ignoring\n");
goto err_exit;
}
for (i = 0; i < 4; i++) {
if (package->package.elements[i].type != ACPI_TYPE_INTEGER) {
err("invalid _HPP parameter type; ignoring");
err("invalid _HPP parameter type; ignoring\n");
goto err_exit;
}
}
......@@ -428,7 +427,7 @@ static void decode_hpp(struct acpiphp_bridge *bridge)
bridge->hpp.enable_SERR = package->package.elements[2].integer.value;
bridge->hpp.enable_PERR = package->package.elements[3].integer.value;
dbg("_HPP parameter = (%02x, %02x, %02x, %02x)",
dbg("_HPP parameter = (%02x, %02x, %02x, %02x)\n",
bridge->hpp.cache_line_size,
bridge->hpp.latency_timer,
bridge->hpp.enable_SERR,
......@@ -463,15 +462,13 @@ static void init_bridge_misc (struct acpiphp_bridge *bridge)
bridge);
if (ACPI_FAILURE(status)) {
err("failed to register interrupt notify handler");
err("failed to register interrupt notify handler\n");
}
list_add(&bridge->list, &bridge_list);
#if 1
dbg("Bridge resource:");
dbg("Bridge resource:\n");
acpiphp_dump_resource(bridge);
#endif
}
......@@ -507,7 +504,7 @@ static void add_host_bridge (acpi_handle *handle, int seg, int bus)
status = acpi_get_current_resources(handle, &buffer);
if (ACPI_FAILURE(status)) {
err("failed to decode bridge resources");
err("failed to decode bridge resources\n");
kfree(bridge);
return;
}
......@@ -535,7 +532,7 @@ static void add_p2p_bridge (acpi_handle *handle, int seg, int bus, int dev, int
bridge = kmalloc(sizeof(struct acpiphp_bridge), GFP_KERNEL);
if (bridge == NULL) {
err("out of memory");
err("out of memory\n");
return;
}
......@@ -547,14 +544,14 @@ static void add_p2p_bridge (acpi_handle *handle, int seg, int bus, int dev, int
bridge->pci_dev = pci_find_slot(bus, PCI_DEVFN(dev, fn));
if (!bridge->pci_dev) {
err("Can't get pci_dev");
err("Can't get pci_dev\n");
kfree(bridge);
return;
}
bridge->pci_bus = bridge->pci_dev->subordinate;
if (!bridge->pci_bus) {
err("This is not a PCI-to-PCI bridge!");
err("This is not a PCI-to-PCI bridge!\n");
kfree(bridge);
return;
}
......@@ -580,10 +577,10 @@ static void add_p2p_bridge (acpi_handle *handle, int seg, int bus, int dev, int
limit = ((limit << 8) & 0xf000) + 0xfff;
bridge->io_head = acpiphp_make_resource((u64)base, limit - base + 1);
if (!bridge->io_head) {
err("out of memory");
err("out of memory\n");
return;
}
dbg("16bit I/O range: %04x-%04x",
dbg("16bit I/O range: %04x-%04x\n",
(u32)bridge->io_head->base,
(u32)(bridge->io_head->base + bridge->io_head->length - 1));
break;
......@@ -594,18 +591,18 @@ static void add_p2p_bridge (acpi_handle *handle, int seg, int bus, int dev, int
limit = (((u32)tmp16 << 16) | ((limit << 8) & 0xf000)) + 0xfff;
bridge->io_head = acpiphp_make_resource((u64)base, limit - base + 1);
if (!bridge->io_head) {
err("out of memory");
err("out of memory\n");
return;
}
dbg("32bit I/O range: %08x-%08x",
dbg("32bit I/O range: %08x-%08x\n",
(u32)bridge->io_head->base,
(u32)(bridge->io_head->base + bridge->io_head->length - 1));
break;
case 0x0f:
dbg("I/O space unsupported");
dbg("I/O space unsupported\n");
break;
default:
warn("Unknown I/O range type");
warn("Unknown I/O range type\n");
}
/* Memory resources (mandatory for P2P bridge) */
......@@ -615,10 +612,10 @@ static void add_p2p_bridge (acpi_handle *handle, int seg, int bus, int dev, int
limit = ((tmp16 & 0xfff0) << 16) | 0xfffff;
bridge->mem_head = acpiphp_make_resource((u64)base, limit - base + 1);
if (!bridge->mem_head) {
err("out of memory");
err("out of memory\n");
return;
}
dbg("32bit Memory range: %08x-%08x",
dbg("32bit Memory range: %08x-%08x\n",
(u32)bridge->mem_head->base,
(u32)(bridge->mem_head->base + bridge->mem_head->length-1));
......@@ -634,10 +631,10 @@ static void add_p2p_bridge (acpi_handle *handle, int seg, int bus, int dev, int
limit = ((limit & 0xfff0) << 16) | 0xfffff;
bridge->p_mem_head = acpiphp_make_resource((u64)base, limit - base + 1);
if (!bridge->p_mem_head) {
err("out of memory");
err("out of memory\n");
return;
}
dbg("32bit Prefetchable memory range: %08x-%08x",
dbg("32bit Prefetchable memory range: %08x-%08x\n",
(u32)bridge->p_mem_head->base,
(u32)(bridge->p_mem_head->base + bridge->p_mem_head->length - 1));
break;
......@@ -649,10 +646,10 @@ static void add_p2p_bridge (acpi_handle *handle, int seg, int bus, int dev, int
bridge->p_mem_head = acpiphp_make_resource(base64, limit64 - base64 + 1);
if (!bridge->p_mem_head) {
err("out of memory");
err("out of memory\n");
return;
}
dbg("64bit Prefetchable memory range: %08x%08x-%08x%08x",
dbg("64bit Prefetchable memory range: %08x%08x-%08x%08x\n",
(u32)(bridge->p_mem_head->base >> 32),
(u32)(bridge->p_mem_head->base & 0xffffffff),
(u32)((bridge->p_mem_head->base + bridge->p_mem_head->length - 1) >> 32),
......@@ -661,7 +658,7 @@ static void add_p2p_bridge (acpi_handle *handle, int seg, int bus, int dev, int
case 0x0f:
break;
default:
warn("Unknown prefetchale memory type");
warn("Unknown prefetchale memory type\n");
}
init_bridge_misc(bridge);
......@@ -689,7 +686,7 @@ find_p2p_bridge (acpi_handle handle, u32 lvl, void *context, void **rv)
status = acpi_evaluate_integer(handle, "_ADR", NULL, &tmp);
if (ACPI_FAILURE(status)) {
dbg("%s: _ADR evaluation failure", __FUNCTION__);
dbg("%s: _ADR evaluation failure\n", __FUNCTION__);
return AE_OK;
}
......@@ -706,7 +703,7 @@ find_p2p_bridge (acpi_handle handle, u32 lvl, void *context, void **rv)
/* check if this bridge has ejectable slots */
if (detect_ejectable_slots(handle) > 0) {
dbg("found PCI-to-PCI bridge at PCI %02x:%02x.%d", bus, device, function);
dbg("found PCI-to-PCI bridge at PCI %s\n", dev->slot_name);
add_p2p_bridge(handle, seg, bus, device, function);
}
......@@ -727,7 +724,7 @@ static int add_bridges (acpi_handle *handle)
if (ACPI_SUCCESS(status)) {
status = acpi_evaluate_integer(handle, "_STA", NULL, &tmp);
if (ACPI_FAILURE(status)) {
dbg("%s: _STA evaluation failure", __FUNCTION__);
dbg("%s: _STA evaluation failure\n", __FUNCTION__);
return 0;
}
if ((tmp & ACPI_STA_FUNCTIONING) == 0)
......@@ -746,13 +743,13 @@ static int add_bridges (acpi_handle *handle)
if (ACPI_SUCCESS(status)) {
bus = tmp;
} else {
warn("can't get bus number, assuming 0");
warn("can't get bus number, assuming 0\n");
bus = 0;
}
/* check if this bridge has ejectable slots */
if (detect_ejectable_slots(handle) > 0) {
dbg("found PCI host-bus bridge with hot-pluggable slots");
dbg("found PCI host-bus bridge with hot-pluggable slots\n");
add_host_bridge(handle, seg, bus);
return 0;
}
......@@ -764,7 +761,7 @@ static int add_bridges (acpi_handle *handle)
find_p2p_bridge, &tmp, NULL);
if (ACPI_FAILURE(status))
warn("find_p2p_bridge faied (error code = 0x%x)",status);
warn("find_p2p_bridge faied (error code = 0x%x)\n",status);
return 0;
}
......@@ -782,7 +779,7 @@ find_host_bridge (acpi_handle handle, u32 lvl, void *context, void **rv)
status = acpi_get_object_info(handle, &info);
if (ACPI_FAILURE(status)) {
dbg("%s: failed to get bridge information", __FUNCTION__);
dbg("%s: failed to get bridge information\n", __FUNCTION__);
return AE_OK; /* continue */
}
......@@ -793,7 +790,7 @@ find_host_bridge (acpi_handle handle, u32 lvl, void *context, void **rv)
(info.valid & ACPI_VALID_HID) &&
strcmp(info.hardware_id, ACPI_PCI_HOST_HID) == 0) {
acpi_get_name(handle, ACPI_SINGLE_NAME, &buffer);
dbg("checking PCI-hotplug capable bridges under [%s]", objname);
dbg("checking PCI-hotplug capable bridges under [%s]\n", objname);
add_bridges(handle);
}
return AE_OK;
......@@ -811,15 +808,15 @@ static int power_on_slot (struct acpiphp_slot *slot)
if (slot->flags & SLOT_POWEREDON)
goto err_exit;
list_for_each(l, &slot->funcs) {
list_for_each (l, &slot->funcs) {
func = list_entry(l, struct acpiphp_func, sibling);
if (func->flags & FUNC_HAS_PS0) {
dbg("%s: executing _PS0 on %02x:%02x.%d", __FUNCTION__,
slot->bridge->bus, slot->device, func->function);
dbg("%s: executing _PS0 on %s\n", __FUNCTION__,
func->pci_dev->slot_name);
status = acpi_evaluate_object(func->handle, "_PS0", NULL, NULL);
if (ACPI_FAILURE(status)) {
warn("%s: _PS0 failed", __FUNCTION__);
warn("%s: _PS0 failed\n", __FUNCTION__);
retval = -1;
goto err_exit;
}
......@@ -849,27 +846,27 @@ static int power_off_slot (struct acpiphp_slot *slot)
if ((slot->flags & SLOT_POWEREDON) == 0)
goto err_exit;
list_for_each(l, &slot->funcs) {
list_for_each (l, &slot->funcs) {
func = list_entry(l, struct acpiphp_func, sibling);
if (func->flags & FUNC_HAS_PS3) {
dbg("%s: executing _PS3 on %02x:%02x.%d", __FUNCTION__,
slot->bridge->bus, slot->device, func->function);
dbg("%s: executing _PS3 on %s\n", __FUNCTION__,
func->pci_dev->slot_name);
status = acpi_evaluate_object(func->handle, "_PS3", NULL, NULL);
if (ACPI_FAILURE(status)) {
warn("%s: _PS3 failed", __FUNCTION__);
warn("%s: _PS3 failed\n", __FUNCTION__);
retval = -1;
goto err_exit;
}
}
}
list_for_each(l, &slot->funcs) {
list_for_each (l, &slot->funcs) {
func = list_entry(l, struct acpiphp_func, sibling);
if (func->flags & FUNC_HAS_EJ0) {
dbg("%s: executing _EJ0 on %02x:%02x.%d", __FUNCTION__,
slot->bridge->bus, slot->device, func->function);
dbg("%s: executing _EJ0 on %s\n", __FUNCTION__,
func->pci_dev->slot_name);
/* _EJ0 method take one argument */
arg_list.count = 1;
......@@ -879,7 +876,7 @@ static int power_off_slot (struct acpiphp_slot *slot)
status = acpi_evaluate_object(func->handle, "_EJ0", &arg_list, NULL);
if (ACPI_FAILURE(status)) {
warn("%s: _EJ0 failed", __FUNCTION__);
warn("%s: _EJ0 failed\n", __FUNCTION__);
retval = -1;
goto err_exit;
}
......@@ -919,7 +916,7 @@ static int enable_device (struct acpiphp_slot *slot)
dev = pci_find_slot(slot->bridge->bus, PCI_DEVFN(slot->device, 0));
if (dev) {
/* This case shouldn't happen */
err("pci_dev structure already exists.");
err("pci_dev structure already exists.\n");
retval = -1;
goto err_exit;
}
......@@ -941,7 +938,7 @@ static int enable_device (struct acpiphp_slot *slot)
dev = pci_scan_slot (&dev0);
if (!dev) {
err("No new device found");
err("No new device found\n");
retval = -1;
goto err_exit;
}
......@@ -953,7 +950,7 @@ static int enable_device (struct acpiphp_slot *slot)
}
/* associate pci_dev to our representation */
list_for_each(l, &slot->funcs) {
list_for_each (l, &slot->funcs) {
func = list_entry(l, struct acpiphp_func, sibling);
func->pci_dev = pci_find_slot(slot->bridge->bus,
......@@ -970,10 +967,8 @@ static int enable_device (struct acpiphp_slot *slot)
slot->flags |= SLOT_ENABLED;
#if 1
dbg("Available resources:");
dbg("Available resources:\n");
acpiphp_dump_resource(slot->bridge);
#endif
err_exit:
return retval;
......@@ -993,14 +988,14 @@ static int disable_device (struct acpiphp_slot *slot)
if (!(slot->flags & SLOT_ENABLED))
goto err_exit;
list_for_each(l, &slot->funcs) {
list_for_each (l, &slot->funcs) {
func = list_entry(l, struct acpiphp_func, sibling);
if (func->pci_dev) {
if (acpiphp_unconfigure_function(func) == 0) {
func->pci_dev = NULL;
} else {
err("failed to unconfigure device");
err("failed to unconfigure device\n");
retval = -1;
goto err_exit;
}
......@@ -1033,7 +1028,7 @@ static unsigned int get_slot_status (struct acpiphp_slot *slot)
struct list_head *l;
struct acpiphp_func *func;
list_for_each(l, &slot->funcs) {
list_for_each (l, &slot->funcs) {
func = list_entry(l, struct acpiphp_func, sibling);
if (func->flags & FUNC_HAS_STA) {
......@@ -1063,7 +1058,7 @@ static unsigned int get_slot_status (struct acpiphp_slot *slot)
/**
* handle_hotplug_event_bridge - handle ACPI event on bridges
*
* @handle: Notify()'ed acpi_handle
* @handle: Notify()'ed acpi_handle
* @type: Notify code
* @context: pointer to acpiphp_bridge structure
*
......@@ -1084,28 +1079,28 @@ static void handle_hotplug_event_bridge (acpi_handle handle, u32 type, void *con
switch (type) {
case ACPI_NOTIFY_BUS_CHECK:
/* bus re-enumerate */
dbg("%s: Bus check notify on %s", __FUNCTION__, objname);
dbg("%s: Bus check notify on %s\n", __FUNCTION__, objname);
acpiphp_check_bridge(bridge);
break;
case ACPI_NOTIFY_DEVICE_CHECK:
/* device check */
dbg("%s: Device check notify on %s", __FUNCTION__, objname);
dbg("%s: Device check notify on %s\n", __FUNCTION__, objname);
acpiphp_check_bridge(bridge);
break;
case ACPI_NOTIFY_DEVICE_WAKE:
/* wake event */
dbg("%s: Device wake notify on %s", __FUNCTION__, objname);
dbg("%s: Device wake notify on %s\n", __FUNCTION__, objname);
break;
case ACPI_NOTIFY_EJECT_REQUEST:
/* request device eject */
dbg("%s: Device eject notify on %s", __FUNCTION__, objname);
dbg("%s: Device eject notify on %s\n", __FUNCTION__, objname);
break;
default:
warn("notify_handler: unknown event type 0x%x for %s", type, objname);
warn("notify_handler: unknown event type 0x%x for %s\n", type, objname);
break;
}
}
......@@ -1114,7 +1109,7 @@ static void handle_hotplug_event_bridge (acpi_handle handle, u32 type, void *con
/**
* handle_hotplug_event_func - handle ACPI event on functions (i.e. slots)
*
* @handle: Notify()'ed acpi_handle
* @handle: Notify()'ed acpi_handle
* @type: Notify code
* @context: pointer to acpiphp_func structure
*
......@@ -1135,29 +1130,29 @@ static void handle_hotplug_event_func (acpi_handle handle, u32 type, void *conte
switch (type) {
case ACPI_NOTIFY_BUS_CHECK:
/* bus re-enumerate */
dbg("%s: Bus check notify on %s", __FUNCTION__, objname);
dbg("%s: Bus check notify on %s\n", __FUNCTION__, objname);
acpiphp_enable_slot(func->slot);
break;
case ACPI_NOTIFY_DEVICE_CHECK:
/* device check : re-enumerate from parent bus */
dbg("%s: Device check notify on %s", __FUNCTION__, objname);
dbg("%s: Device check notify on %s\n", __FUNCTION__, objname);
acpiphp_check_bridge(func->slot->bridge);
break;
case ACPI_NOTIFY_DEVICE_WAKE:
/* wake event */
dbg("%s: Device wake notify on %s", __FUNCTION__, objname);
dbg("%s: Device wake notify on %s\n", __FUNCTION__, objname);
break;
case ACPI_NOTIFY_EJECT_REQUEST:
/* request device eject */
dbg("%s: Device eject notify on %s", __FUNCTION__, objname);
dbg("%s: Device eject notify on %s\n", __FUNCTION__, objname);
acpiphp_disable_slot(func->slot);
break;
default:
warn("notify_handler: unknown event type 0x%x for %s", type, objname);
warn("notify_handler: unknown event type 0x%x for %s\n", type, objname);
break;
}
}
......@@ -1179,7 +1174,7 @@ int acpiphp_glue_init (void)
NULL, NULL);
if (ACPI_FAILURE(status)) {
err("%s: acpi_walk_namespace() failed", __FUNCTION__);
err("%s: acpi_walk_namespace() failed\n", __FUNCTION__);
return -1;
}
......@@ -1200,12 +1195,12 @@ void acpiphp_glue_exit (void)
struct acpiphp_func *func;
acpi_status status;
list_for_each_safe(l1, n1, &bridge_list) {
list_for_each_safe (l1, n1, &bridge_list) {
bridge = (struct acpiphp_bridge *)l1;
slot = bridge->slots;
while (slot) {
next = slot->next;
list_for_each_safe(l2, n2, &slot->funcs) {
list_for_each_safe (l2, n2, &slot->funcs) {
func = list_entry(l2, struct acpiphp_func, sibling);
acpiphp_free_resource(&func->io_head);
acpiphp_free_resource(&func->mem_head);
......@@ -1215,7 +1210,7 @@ void acpiphp_glue_exit (void)
ACPI_SYSTEM_NOTIFY,
handle_hotplug_event_func);
if (ACPI_FAILURE(status))
err("failed to remove notify handler");
err("failed to remove notify handler\n");
kfree(func);
}
kfree(slot);
......@@ -1224,7 +1219,7 @@ void acpiphp_glue_exit (void)
status = acpi_remove_notify_handler(bridge->handle, ACPI_SYSTEM_NOTIFY,
handle_hotplug_event_bridge);
if (ACPI_FAILURE(status))
err("failed to remove notify handler");
err("failed to remove notify handler\n");
acpiphp_free_resource(&bridge->io_head);
acpiphp_free_resource(&bridge->mem_head);
......@@ -1247,13 +1242,13 @@ int acpiphp_get_num_slots (void)
num_slots = 0;
list_for_each(node, &bridge_list) {
list_for_each (node, &bridge_list) {
bridge = (struct acpiphp_bridge *)node;
dbg("Bus%d %dslot(s)", bridge->bus, bridge->nr_slots);
dbg("Bus%d %dslot(s)\n", bridge->bus, bridge->nr_slots);
num_slots += bridge->nr_slots;
}
dbg("Total %dslots", num_slots);
dbg("Total %dslots\n", num_slots);
return num_slots;
}
......@@ -1271,7 +1266,7 @@ int acpiphp_for_each_slot(acpiphp_callback fn, void *data)
struct acpiphp_slot *slot;
int retval = 0;
list_for_each(node, &bridge_list) {
list_for_each (node, &bridge_list) {
bridge = (struct acpiphp_bridge *)node;
for (slot = bridge->slots; slot; slot = slot->next) {
retval = fn(slot, data);
......@@ -1292,7 +1287,7 @@ struct acpiphp_slot *get_slot_from_id (int id)
struct acpiphp_bridge *bridge;
struct acpiphp_slot *slot;
list_for_each(node, &bridge_list) {
list_for_each (node, &bridge_list) {
bridge = (struct acpiphp_bridge *)node;
for (slot = bridge->slots; slot; slot = slot->next)
if (slot->id == id)
......@@ -1300,7 +1295,7 @@ struct acpiphp_slot *get_slot_from_id (int id)
}
/* should never happen! */
err("%s: no object for id %d",__FUNCTION__, id);
err("%s: no object for id %d\n",__FUNCTION__, id);
return 0;
}
......@@ -1352,7 +1347,7 @@ int acpiphp_disable_slot (struct acpiphp_slot *slot)
acpiphp_resource_sort_and_combine(&slot->bridge->mem_head);
acpiphp_resource_sort_and_combine(&slot->bridge->p_mem_head);
acpiphp_resource_sort_and_combine(&slot->bridge->bus_head);
dbg("Available resources:");
dbg("Available resources:\n");
acpiphp_dump_resource(slot->bridge);
err_exit:
......@@ -1380,7 +1375,7 @@ int acpiphp_check_bridge (struct acpiphp_bridge *bridge)
if (sta != ACPI_STA_ALL) {
retval = acpiphp_disable_slot(slot);
if (retval) {
err("Error occured in enabling");
err("Error occured in enabling\n");
up(&slot->crit_sect);
goto err_exit;
}
......@@ -1391,7 +1386,7 @@ int acpiphp_check_bridge (struct acpiphp_bridge *bridge)
if (sta == ACPI_STA_ALL) {
retval = acpiphp_enable_slot(slot);
if (retval) {
err("Error occured in enabling");
err("Error occured in enabling\n");
up(&slot->crit_sect);
goto err_exit;
}
......@@ -1400,7 +1395,7 @@ int acpiphp_check_bridge (struct acpiphp_bridge *bridge)
}
}
dbg("%s: %d enabled, %d disabled", __FUNCTION__, enabled, disabled);
dbg("%s: %d enabled, %d disabled\n", __FUNCTION__, enabled, disabled);
err_exit:
return retval;
......
......@@ -77,7 +77,7 @@ static int init_config_space (struct acpiphp_func *func)
if (!bar) /* This BAR is not implemented */
continue;
dbg("Device %02x.%02x BAR %d wants %x", device, function, count, bar);
dbg("Device %02x.%02x BAR %d wants %x\n", device, function, count, bar);
if (bar & PCI_BASE_ADDRESS_SPACE_IO) {
/* This is IO */
......@@ -85,7 +85,7 @@ static int init_config_space (struct acpiphp_func *func)
len = bar & 0xFFFFFFFC;
len = ~len + 1;
dbg ("len in IO %x, BAR %d", len, count);
dbg("len in IO %x, BAR %d\n", len, count);
spin_lock(&bridge->res_lock);
res = acpiphp_get_io_resource(&bridge->io_head, len);
......@@ -110,7 +110,7 @@ static int init_config_space (struct acpiphp_func *func)
len = bar & 0xFFFFFFF0;
len = ~len + 1;
dbg("len in PFMEM %x, BAR %d", len, count);
dbg("len in PFMEM %x, BAR %d\n", len, count);
spin_lock(&bridge->res_lock);
res = acpiphp_get_resource(&bridge->p_mem_head, len);
......@@ -127,7 +127,7 @@ static int init_config_space (struct acpiphp_func *func)
(u32)res->base);
if (bar & PCI_BASE_ADDRESS_MEM_TYPE_64) { /* takes up another dword */
dbg ("inside the pfmem 64 case, count %d", count);
dbg("inside the pfmem 64 case, count %d\n", count);
count += 1;
pci_bus_write_config_dword(pbus, devfn,
address[count],
......@@ -143,7 +143,7 @@ static int init_config_space (struct acpiphp_func *func)
len = bar & 0xFFFFFFF0;
len = ~len + 1;
dbg("len in MEM %x, BAR %d", len, count);
dbg("len in MEM %x, BAR %d\n", len, count);
spin_lock(&bridge->res_lock);
res = acpiphp_get_resource(&bridge->mem_head, len);
......@@ -161,7 +161,7 @@ static int init_config_space (struct acpiphp_func *func)
if (bar & PCI_BASE_ADDRESS_MEM_TYPE_64) {
/* takes up another dword */
dbg ("inside mem 64 case, reg. mem, count %d", count);
dbg("inside mem 64 case, reg. mem, count %d\n", count);
count += 1;
pci_bus_write_config_dword(pbus, devfn,
address[count],
......@@ -212,16 +212,16 @@ static int configure_pci_dev (struct pci_dev_wrapped *wrapped_dev, struct pci_bu
//pci_proc_attach_device(dev);
//pci_announce_device_to_drivers(dev);
info("Device %s configured", dev->slot_name);
info("Device %s configured\n", dev->slot_name);
return 0;
}
static int is_pci_dev_in_use (struct pci_dev* dev)
static int is_pci_dev_in_use (struct pci_dev* dev)
{
/*
* dev->driver will be set if the device is in use by a new-style
/*
* dev->driver will be set if the device is in use by a new-style
* driver -- otherwise, check the device's regions to see if any
* driver has claimed them
*/
......@@ -263,13 +263,13 @@ static int unconfigure_pci_dev_driver (struct pci_dev_wrapped *wrapped_dev, stru
{
struct pci_dev *dev = wrapped_dev->dev;
dbg("attempting removal of driver for device %s", dev->slot_name);
dbg("attempting removal of driver for device %s\n", dev->slot_name);
/* Now, remove the Linux Driver Representation */
if (dev->driver) {
if (dev->driver->remove) {
dev->driver->remove(dev);
dbg("driver was properly removed");
dbg("driver was properly removed\n");
}
dev->driver = NULL;
}
......@@ -286,7 +286,7 @@ static int unconfigure_pci_dev (struct pci_dev_wrapped *wrapped_dev, struct pci_
/* Now, remove the Linux Representation */
if (dev) {
if (pci_hp_remove_device(dev) == 0) {
info("Device %s removed", dev->slot_name);
info("Device %s removed\n", dev->slot_name);
kfree(dev); /* Now, remove */
} else {
return -1; /* problems while freeing, abort visitation */
......@@ -338,7 +338,7 @@ static int detect_used_resource (struct acpiphp_bridge *bridge, struct pci_dev *
int count;
struct pci_resource *res;
dbg("Device %s", dev->slot_name);
dbg("Device %s\n", dev->slot_name);
for (count = 0; address[count]; count++) { /* for 6 BARs */
pci_read_config_dword(dev, address[count], &bar);
......@@ -355,7 +355,7 @@ static int detect_used_resource (struct acpiphp_bridge *bridge, struct pci_dev *
len &= 0xFFFFFFFC;
len = ~len + 1;
dbg("BAR[%d] %08x - %08x (IO)", count, (u32)base, (u32)base + len - 1);
dbg("BAR[%d] %08x - %08x (IO)\n", count, (u32)base, (u32)base + len - 1);
spin_lock(&bridge->res_lock);
res = acpiphp_get_resource_with_base(&bridge->io_head, base, len);
......@@ -372,10 +372,10 @@ static int detect_used_resource (struct acpiphp_bridge *bridge, struct pci_dev *
len = ~len + 1;
if (len & PCI_BASE_ADDRESS_MEM_TYPE_64) { /* takes up another dword */
dbg ("prefetch mem 64");
dbg("prefetch mem 64\n");
count += 1;
}
dbg("BAR[%d] %08x - %08x (PMEM)", count, (u32)base, (u32)base + len - 1);
dbg("BAR[%d] %08x - %08x (PMEM)\n", count, (u32)base, (u32)base + len - 1);
spin_lock(&bridge->res_lock);
res = acpiphp_get_resource_with_base(&bridge->p_mem_head, base, len);
spin_unlock(&bridge->res_lock);
......@@ -389,10 +389,10 @@ static int detect_used_resource (struct acpiphp_bridge *bridge, struct pci_dev *
if (len & PCI_BASE_ADDRESS_MEM_TYPE_64) {
/* takes up another dword */
dbg ("mem 64");
dbg("mem 64\n");
count += 1;
}
dbg("BAR[%d] %08x - %08x (MEM)", count, (u32)base, (u32)base + len - 1);
dbg("BAR[%d] %08x - %08x (MEM)\n", count, (u32)base, (u32)base + len - 1);
spin_lock(&bridge->res_lock);
res = acpiphp_get_resource_with_base(&bridge->mem_head, base, len);
spin_unlock(&bridge->res_lock);
......@@ -414,7 +414,7 @@ static void detect_used_resource_bus(struct acpiphp_bridge *bridge, struct pci_b
struct list_head *l;
struct pci_dev *dev;
list_for_each(l, &bus->devices) {
list_for_each (l, &bus->devices) {
dev = pci_dev_b(l);
detect_used_resource(bridge, dev);
/* XXX recursive call */
......@@ -463,16 +463,16 @@ int acpiphp_init_func_resource (struct acpiphp_func *func)
struct pci_dev *dev;
dev = func->pci_dev;
dbg("Hot-pluggable device %s", dev->slot_name);
dbg("Hot-pluggable device %s\n", dev->slot_name);
for (count = 0; address[count]; count++) { /* for 6 BARs */
pci_read_config_dword (dev, address[count], &bar);
pci_read_config_dword(dev, address[count], &bar);
if (!bar) /* This BAR is not implemented */
continue;
pci_write_config_dword (dev, address[count], 0xFFFFFFFF);
pci_read_config_dword (dev, address[count], &len);
pci_write_config_dword(dev, address[count], 0xFFFFFFFF);
pci_read_config_dword(dev, address[count], &len);
if (len & PCI_BASE_ADDRESS_SPACE_IO) {
/* This is IO */
......@@ -480,7 +480,7 @@ int acpiphp_init_func_resource (struct acpiphp_func *func)
len &= 0xFFFFFFFC;
len = ~len + 1;
dbg("BAR[%d] %08x - %08x (IO)", count, (u32)base, (u32)base + len - 1);
dbg("BAR[%d] %08x - %08x (IO)\n", count, (u32)base, (u32)base + len - 1);
res = acpiphp_make_resource(base, len);
if (!res)
......@@ -499,10 +499,10 @@ int acpiphp_init_func_resource (struct acpiphp_func *func)
len = ~len + 1;
if (len & PCI_BASE_ADDRESS_MEM_TYPE_64) { /* takes up another dword */
dbg ("prefetch mem 64");
dbg("prefetch mem 64\n");
count += 1;
}
dbg("BAR[%d] %08x - %08x (PMEM)", count, (u32)base, (u32)base + len - 1);
dbg("BAR[%d] %08x - %08x (PMEM)\n", count, (u32)base, (u32)base + len - 1);
res = acpiphp_make_resource(base, len);
if (!res)
goto no_memory;
......@@ -518,10 +518,10 @@ int acpiphp_init_func_resource (struct acpiphp_func *func)
if (len & PCI_BASE_ADDRESS_MEM_TYPE_64) {
/* takes up another dword */
dbg ("mem 64");
dbg("mem 64\n");
count += 1;
}
dbg("BAR[%d] %08x - %08x (MEM)", count, (u32)base, (u32)base + len - 1);
dbg("BAR[%d] %08x - %08x (MEM)\n", count, (u32)base, (u32)base + len - 1);
res = acpiphp_make_resource(base, len);
if (!res)
goto no_memory;
......@@ -532,7 +532,7 @@ int acpiphp_init_func_resource (struct acpiphp_func *func)
}
}
pci_write_config_dword (dev, address[count], bar);
pci_write_config_dword(dev, address[count], bar);
}
#if 1
acpiphp_dump_func_resource(func);
......@@ -541,7 +541,7 @@ int acpiphp_init_func_resource (struct acpiphp_func *func)
return 0;
no_memory:
err("out of memory");
err("out of memory\n");
acpiphp_free_resource(&func->io_head);
acpiphp_free_resource(&func->mem_head);
acpiphp_free_resource(&func->p_mem_head);
......@@ -574,7 +574,7 @@ int acpiphp_configure_slot (struct acpiphp_slot *slot)
if (hdr & 0x80)
is_multi = 1;
list_for_each(l, &slot->funcs) {
list_for_each (l, &slot->funcs) {
func = list_entry(l, struct acpiphp_func, sibling);
if (is_multi || func->function == 0) {
pci_bus_read_config_dword(slot->bridge->pci_bus,
......@@ -583,7 +583,6 @@ int acpiphp_configure_slot (struct acpiphp_slot *slot)
PCI_VENDOR_ID, &dvid);
if (dvid != 0xffffffff) {
retval = init_config_space(func);
if (retval)
break;
}
......
......@@ -273,7 +273,7 @@ struct pci_resource *acpiphp_get_max_resource (struct pci_resource **head, u32 s
for (max = *head;max; max = max->next) {
/* If not big enough we could probably just bail,
/* If not big enough we could probably just bail,
instead we'll continue to the next. */
if (max->length < size)
continue;
......@@ -370,13 +370,13 @@ struct pci_resource *acpiphp_get_resource (struct pci_resource **head, u32 size)
return NULL;
for (node = *head; node; node = node->next) {
dbg("%s: req_size =%x node=%p, base=%x, length=%x",
dbg("%s: req_size =%x node=%p, base=%x, length=%x\n",
__FUNCTION__, size, node, (u32)node->base, node->length);
if (node->length < size)
continue;
if (node->base & (size - 1)) {
dbg("%s: not aligned", __FUNCTION__);
dbg("%s: not aligned\n", __FUNCTION__);
/* this one isn't base aligned properly
so we'll make a new entry and split it up */
temp_qword = (node->base | (size-1)) + 1;
......@@ -400,7 +400,7 @@ struct pci_resource *acpiphp_get_resource (struct pci_resource **head, u32 size)
/* Don't need to check if too small since we already did */
if (node->length > size) {
dbg("%s: too big", __FUNCTION__);
dbg("%s: too big\n", __FUNCTION__);
/* this one is longer than we need
so we'll make a new entry and split it up */
split_node = acpiphp_make_resource(node->base + size, node->length - size);
......@@ -415,7 +415,7 @@ struct pci_resource *acpiphp_get_resource (struct pci_resource **head, u32 size)
node->next = split_node;
} /* End of too big on top end */
dbg("%s: got one!!!", __FUNCTION__);
dbg("%s: got one!!!\n", __FUNCTION__);
/* If we got here, then it is the right size
Now take it out of the list */
if (*head == node) {
......@@ -437,7 +437,7 @@ struct pci_resource *acpiphp_get_resource (struct pci_resource **head, u32 size)
/**
* get_resource_with_base - get resource with specific base address
*
* this function
* this function
* returns the first node of "size" length located at specified base address.
* If it finds a node larger than "size" it will split it up.
*
......@@ -458,7 +458,7 @@ struct pci_resource *acpiphp_get_resource_with_base (struct pci_resource **head,
return NULL;
for (node = *head; node; node = node->next) {
dbg(": 1st req_base=%x req_size =%x node=%p, base=%x, length=%x",
dbg(": 1st req_base=%x req_size =%x node=%p, base=%x, length=%x\n",
(u32)base, size, node, (u32)node->base, node->length);
if (node->base > base)
continue;
......@@ -467,7 +467,7 @@ struct pci_resource *acpiphp_get_resource_with_base (struct pci_resource **head,
continue;
if (node->base < base) {
dbg(": split 1");
dbg(": split 1\n");
/* this one isn't base aligned properly
so we'll make a new entry and split it up */
temp_qword = base;
......@@ -489,12 +489,12 @@ struct pci_resource *acpiphp_get_resource_with_base (struct pci_resource **head,
node->next = split_node;
}
dbg(": 2nd req_base=%x req_size =%x node=%p, base=%x, length=%x",
dbg(": 2nd req_base=%x req_size =%x node=%p, base=%x, length=%x\n",
(u32)base, size, node, (u32)node->base, node->length);
/* Don't need to check if too small since we already did */
if (node->length > size) {
dbg(": split 2");
dbg(": split 2\n");
/* this one is longer than we need
so we'll make a new entry and split it up */
split_node = acpiphp_make_resource(node->base + size, node->length - size);
......@@ -509,7 +509,7 @@ struct pci_resource *acpiphp_get_resource_with_base (struct pci_resource **head,
node->next = split_node;
} /* End of too big on top end */
dbg(": got one!!!");
dbg(": got one!!!\n");
/* If we got here, then it is the right size
Now take it out of the list */
if (*head == node) {
......@@ -547,13 +547,13 @@ int acpiphp_resource_sort_and_combine (struct pci_resource **head)
if (!(*head))
return 1;
dbg("*head->next = %p",(*head)->next);
dbg("*head->next = %p\n",(*head)->next);
if (!(*head)->next)
return 0; /* only one item on the list, already sorted! */
dbg("*head->base = 0x%x",(u32)(*head)->base);
dbg("*head->next->base = 0x%x", (u32)(*head)->next->base);
dbg("*head->base = 0x%x\n",(u32)(*head)->base);
dbg("*head->next->base = 0x%x\n", (u32)(*head)->next->base);
while (out_of_order) {
out_of_order = 0;
......@@ -587,7 +587,7 @@ int acpiphp_resource_sort_and_combine (struct pci_resource **head)
while (node1 && node1->next) {
if ((node1->base + node1->length) == node1->next->base) {
/* Combine */
dbg("8..");
dbg("8..\n");
node1->length += node1->next->length;
node2 = node1->next;
node1->next = node1->next->next;
......@@ -668,7 +668,7 @@ static void dump_resource(struct pci_resource *head)
cnt = 0;
while (p) {
dbg("[%02d] %08x - %08x",
dbg("[%02d] %08x - %08x\n",
cnt++, (u32)p->base, (u32)p->base + p->length - 1);
p = p->next;
}
......@@ -676,24 +676,24 @@ static void dump_resource(struct pci_resource *head)
void acpiphp_dump_resource(struct acpiphp_bridge *bridge)
{
dbg("I/O resource:");
dbg("I/O resource:\n");
dump_resource(bridge->io_head);
dbg("MEM resource:");
dbg("MEM resource:\n");
dump_resource(bridge->mem_head);
dbg("PMEM resource:");
dbg("PMEM resource:\n");
dump_resource(bridge->p_mem_head);
dbg("BUS resource:");
dbg("BUS resource:\n");
dump_resource(bridge->bus_head);
}
void acpiphp_dump_func_resource(struct acpiphp_func *func)
{
dbg("I/O resource:");
dbg("I/O resource:\n");
dump_resource(func->io_head);
dbg("MEM resource:");
dbg("MEM resource:\n");
dump_resource(func->mem_head);
dbg("PMEM resource:");
dbg("PMEM resource:\n");
dump_resource(func->p_mem_head);
dbg("BUS resource:");
dbg("BUS resource:\n");
dump_resource(func->bus_head);
}
/*
* CompactPCI Hot Plug Core Functions
*
* Copyright (c) 2002 SOMA Networks, Inc.
* Copyright (c) 2001 Greg Kroah-Hartman (greg@kroah.com)
* Copyright (c) 2001 IBM Corp.
*
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or (at
* your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
* NON INFRINGEMENT. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* Send feedback to <scottm@somanetworks.com>
*/
#ifndef _CPCI_HOTPLUG_H
#define _CPCI_HOTPLUG_H
#include <linux/types.h>
#include <linux/pci.h>
/* PICMG 2.12 R2.0 HS CSR bits: */
#define HS_CSR_INS 0x0080
#define HS_CSR_EXT 0x0040
#define HS_CSR_PI 0x0030
#define HS_CSR_LOO 0x0008
#define HS_CSR_PIE 0x0004
#define HS_CSR_EIM 0x0002
#define HS_CSR_DHA 0x0001
#define SLOT_MAGIC 0x67267322
struct slot {
u32 magic;
u8 number;
unsigned int devfn;
struct pci_bus *bus;
struct pci_dev *dev;
unsigned int extracting;
struct hotplug_slot *hotplug_slot;
struct list_head slot_list;
};
struct cpci_hp_controller_ops {
int (*query_enum) (void);
int (*enable_irq) (void);
int (*disable_irq) (void);
int (*check_irq) (void *dev_id);
int (*hardware_test) (struct slot* slot, u32 value);
u8 (*get_power) (struct slot* slot);
int (*set_power) (struct slot* slot, int value);
};
struct cpci_hp_controller {
unsigned int irq;
unsigned long irq_flags;
char *devname;
void *dev_id;
char *name;
struct cpci_hp_controller_ops *ops;
};
extern int cpci_hp_register_controller(struct cpci_hp_controller *controller);
extern int cpci_hp_unregister_controller(struct cpci_hp_controller *controller);
extern int cpci_hp_register_bus(struct pci_bus *bus, u8 first, u8 last);
extern int cpci_hp_unregister_bus(struct pci_bus *bus);
extern struct slot *cpci_find_slot(struct pci_bus *bus, unsigned int devfn);
extern int cpci_hp_start(void);
extern int cpci_hp_stop(void);
/*
* Internal function prototypes, these functions should not be used by
* board/chassis drivers.
*/
extern u8 cpci_get_attention_status(struct slot *slot);
extern u8 cpci_get_latch_status(struct slot *slot);
extern u8 cpci_get_adapter_status(struct slot *slot);
extern u16 cpci_get_hs_csr(struct slot * slot);
extern u16 cpci_set_hs_csr(struct slot * slot, u16 hs_csr);
extern int cpci_set_attention_status(struct slot *slot, int status);
extern int cpci_check_and_clear_ins(struct slot * slot);
extern int cpci_check_ext(struct slot * slot);
extern int cpci_clear_ext(struct slot * slot);
extern int cpci_led_on(struct slot * slot);
extern int cpci_led_off(struct slot * slot);
extern int cpci_configure_slot(struct slot *slot);
extern int cpci_unconfigure_slot(struct slot *slot);
#endif /* _CPCI_HOTPLUG_H */
/*
* CompactPCI Hot Plug Driver
*
* Copyright (c) 2002 SOMA Networks, Inc.
* Copyright (c) 2001 Greg Kroah-Hartman (greg@kroah.com)
* Copyright (c) 2001 IBM Corp.
*
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or (at
* your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
* NON INFRINGEMENT. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* Send feedback to <scottm@somanetworks.com>
*/
#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/pci.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/smp_lock.h>
#include "pci_hotplug.h"
#include "cpci_hotplug.h"
#define DRIVER_VERSION "0.2"
#define DRIVER_AUTHOR "Scott Murray <scottm@somanetworks.com>"
#define DRIVER_DESC "CompactPCI Hot Plug Core"
#if !defined(CONFIG_HOTPLUG_CPCI_MODULE)
#define MY_NAME "cpci_hotplug"
#else
#define MY_NAME THIS_MODULE->name
#endif
#define dbg(format, arg...) \
do { \
if(cpci_debug) \
printk (KERN_DEBUG "%s: " format "\n", \
MY_NAME , ## arg); \
} while(0)
#define err(format, arg...) printk(KERN_ERR "%s: " format "\n", MY_NAME , ## arg)
#define info(format, arg...) printk(KERN_INFO "%s: " format "\n", MY_NAME , ## arg)
#define warn(format, arg...) printk(KERN_WARNING "%s: " format "\n", MY_NAME , ## arg)
/* local variables */
static spinlock_t list_lock;
static LIST_HEAD(slot_list);
static int slots;
int cpci_debug;
static struct cpci_hp_controller *controller;
static struct semaphore event_semaphore; /* mutex for process loop (up if something to process) */
static struct semaphore thread_exit; /* guard ensure thread has exited before calling it quits */
static int thread_finished = 1;
static int enable_slot(struct hotplug_slot *slot);
static int disable_slot(struct hotplug_slot *slot);
static int set_attention_status(struct hotplug_slot *slot, u8 value);
static int get_power_status(struct hotplug_slot *slot, u8 * value);
static int get_attention_status(struct hotplug_slot *slot, u8 * value);
static int get_latch_status(struct hotplug_slot *slot, u8 * value);
static int get_adapter_status(struct hotplug_slot *slot, u8 * value);
static struct hotplug_slot_ops cpci_hotplug_slot_ops = {
.owner = THIS_MODULE,
.enable_slot = enable_slot,
.disable_slot = disable_slot,
.set_attention_status = set_attention_status,
.hardware_test = NULL,
.get_power_status = get_power_status,
.get_attention_status = get_attention_status,
.get_latch_status = get_latch_status,
.get_adapter_status = get_adapter_status,
};
/* Inline functions to check the sanity of a pointer that is passed to us */
static inline int
slot_paranoia_check(struct slot *slot, const char *function)
{
if(!slot) {
dbg("%s - slot == NULL", function);
return -1;
}
if(slot->magic != SLOT_MAGIC) {
dbg("%s - bad magic number for slot", function);
return -1;
}
if(!slot->hotplug_slot) {
dbg("%s - slot->hotplug_slot == NULL!", function);
return -1;
}
return 0;
}
static inline struct slot *
get_slot(struct hotplug_slot *hotplug_slot, const char *function)
{
struct slot *slot;
if(!hotplug_slot) {
dbg("%s - hotplug_slot == NULL", function);
return NULL;
}
slot = (struct slot *) hotplug_slot->private;
if(slot_paranoia_check(slot, function))
return NULL;
return slot;
}
static int
update_latch_status(struct hotplug_slot *hotplug_slot, u8 value)
{
struct hotplug_slot_info info;
if(!(hotplug_slot && hotplug_slot->info))
return -EINVAL;
memcpy(&info, hotplug_slot->info, sizeof(struct hotplug_slot_info));
info.latch_status = value;
return pci_hp_change_slot_info(hotplug_slot->name, &info);
}
static int
update_adapter_status(struct hotplug_slot *hotplug_slot, u8 value)
{
struct hotplug_slot_info info;
if(!(hotplug_slot && hotplug_slot->info))
return -EINVAL;
memcpy(&info, hotplug_slot->info, sizeof(struct hotplug_slot_info));
info.adapter_status = value;
return pci_hp_change_slot_info(hotplug_slot->name, &info);
}
static int
enable_slot(struct hotplug_slot *hotplug_slot)
{
struct slot *slot = get_slot(hotplug_slot, __FUNCTION__);
int retval = 0;
if(slot == NULL)
return -ENODEV;
dbg("%s - physical_slot = %s", __FUNCTION__, hotplug_slot->name);
if(controller->ops->set_power) {
retval = controller->ops->set_power(slot, 1);
}
return retval;
}
static int
disable_slot(struct hotplug_slot *hotplug_slot)
{
struct slot *slot = get_slot(hotplug_slot, __FUNCTION__);
int retval = 0;
if(slot == NULL)
return -ENODEV;
dbg("%s - physical_slot = %s", __FUNCTION__, hotplug_slot->name);
/* Unconfigure device */
dbg("%s - unconfiguring slot %s",
__FUNCTION__, slot->hotplug_slot->name);
if((retval = cpci_unconfigure_slot(slot))) {
err("%s - could not unconfigure slot %s",
__FUNCTION__, slot->hotplug_slot->name);
return retval;
}
dbg("%s - finished unconfiguring slot %s",
__FUNCTION__, slot->hotplug_slot->name);
/* Clear EXT (by setting it) */
if(cpci_clear_ext(slot)) {
err("%s - could not clear EXT for slot %s",
__FUNCTION__, slot->hotplug_slot->name);
retval = -ENODEV;
}
cpci_led_on(slot);
if(controller->ops->set_power) {
retval = controller->ops->set_power(slot, 0);
}
if(update_adapter_status(slot->hotplug_slot, 0)) {
warn("failure to update adapter file");
}
slot->extracting = 0;
return retval;
}
static u8
cpci_get_power_status(struct slot *slot)
{
u8 power = 1;
if(controller->ops->get_power) {
power = controller->ops->get_power(slot);
}
return power;
}
static int
get_power_status(struct hotplug_slot *hotplug_slot, u8 * value)
{
struct slot *slot = get_slot(hotplug_slot, __FUNCTION__);
if(slot == NULL)
return -ENODEV;
*value = cpci_get_power_status(slot);
return 0;
}
static int
get_attention_status(struct hotplug_slot *hotplug_slot, u8 * value)
{
struct slot *slot = get_slot(hotplug_slot, __FUNCTION__);
if(slot == NULL)
return -ENODEV;
*value = cpci_get_attention_status(slot);
return 0;
}
static int
set_attention_status(struct hotplug_slot *hotplug_slot, u8 status)
{
struct slot *slot = get_slot(hotplug_slot, __FUNCTION__);
if(slot == NULL)
return -ENODEV;
switch (status) {
case 0:
cpci_set_attention_status(slot, 0);
break;
case 1:
default:
cpci_set_attention_status(slot, 1);
break;
}
return 0;
}
static int
get_latch_status(struct hotplug_slot *hotplug_slot, u8 * value)
{
if(hotplug_slot == NULL || hotplug_slot->info == NULL)
return -ENODEV;
*value = hotplug_slot->info->latch_status;
return 0;
}
static int
get_adapter_status(struct hotplug_slot *hotplug_slot, u8 * value)
{
if(hotplug_slot == NULL || hotplug_slot->info == NULL)
return -ENODEV;
*value = hotplug_slot->info->adapter_status;
return 0;
}
#define SLOT_NAME_SIZE 6
static void
make_slot_name(struct slot *slot)
{
snprintf(slot->hotplug_slot->name,
SLOT_NAME_SIZE, "%02x:%02x", slot->bus->number, slot->number);
}
int
cpci_hp_register_bus(struct pci_bus *bus, u8 first, u8 last)
{
struct slot *slot;
struct hotplug_slot *hotplug_slot;
struct hotplug_slot_info *info;
char *name;
int status = 0;
int i;
if(!(controller && bus)) {
return -ENODEV;
}
if(last < first) {
return -EINVAL;
}
/*
* Create a structure for each slot, and register that slot
* with the pci_hotplug subsystem.
*/
for (i = first; i <= last; ++i) {
slot = kmalloc(sizeof (struct slot), GFP_KERNEL);
if(!slot)
return -ENOMEM;
memset(slot, 0, sizeof (struct slot));
hotplug_slot =
kmalloc(sizeof (struct hotplug_slot), GFP_KERNEL);
if(!hotplug_slot) {
kfree(slot);
return -ENOMEM;
}
memset(hotplug_slot, 0, sizeof (struct hotplug_slot));
slot->hotplug_slot = hotplug_slot;
info = kmalloc(sizeof (struct hotplug_slot_info), GFP_KERNEL);
if(!info) {
kfree(hotplug_slot);
kfree(slot);
return -ENOMEM;
}
memset(info, 0, sizeof (struct hotplug_slot_info));
hotplug_slot->info = info;
name = kmalloc(SLOT_NAME_SIZE, GFP_KERNEL);
if(!name) {
kfree(info);
kfree(hotplug_slot);
kfree(slot);
return -ENOMEM;
}
hotplug_slot->name = name;
slot->magic = SLOT_MAGIC;
slot->bus = bus;
slot->number = i;
slot->devfn = PCI_DEVFN(i, 0);
hotplug_slot->private = slot;
make_slot_name(slot);
hotplug_slot->ops = &cpci_hotplug_slot_ops;
/*
* Initialize the slot info structure with some known
* good values.
*/
dbg("initializing slot %s", slot->hotplug_slot->name);
info->power_status = cpci_get_power_status(slot);
info->attention_status = cpci_get_attention_status(slot);
dbg("registering slot %s", slot->hotplug_slot->name);
status = pci_hp_register(slot->hotplug_slot);
if(status) {
err("pci_hp_register failed with error %d", status);
kfree(info);
kfree(name);
kfree(hotplug_slot);
kfree(slot);
return status;
}
/* Add slot to our internal list */
spin_lock(&list_lock);
list_add(&slot->slot_list, &slot_list);
slots++;
spin_unlock(&list_lock);
}
return status;
}
int
cpci_hp_unregister_bus(struct pci_bus *bus)
{
struct slot *slot;
struct list_head *tmp;
int status;
if(!bus) {
return -ENODEV;
}
spin_lock(&list_lock);
if(!slots) {
spin_unlock(&list_lock);
return -1;
}
list_for_each(tmp, &slot_list) {
slot = list_entry(tmp, struct slot, slot_list);
if(slot->bus == bus) {
dbg("deregistering slot %s", slot->hotplug_slot->name);
status = pci_hp_deregister(slot->hotplug_slot);
if(status) {
err("pci_hp_deregister failed with error %d",
status);
return status;
}
list_del(&slot->slot_list);
kfree(slot->hotplug_slot->info);
kfree(slot->hotplug_slot->name);
kfree(slot->hotplug_slot);
kfree(slot);
slots--;
}
}
spin_unlock(&list_lock);
return 0;
}
struct slot *
cpci_find_slot(struct pci_bus *bus, unsigned int devfn)
{
struct slot *slot;
struct slot *found;
struct list_head *tmp;
if(!bus) {
return NULL;
}
spin_lock(&list_lock);
if(!slots) {
spin_unlock(&list_lock);
return NULL;
}
found = NULL;
list_for_each(tmp, &slot_list) {
slot = list_entry(tmp, struct slot, slot_list);
if(slot->bus == bus && slot->devfn == devfn) {
found = slot;
break;
}
}
spin_unlock(&list_lock);
return found;
}
/* This is the interrupt mode interrupt handler */
void
cpci_hp_intr(int irq, void *data, struct pt_regs *regs)
{
dbg("entered cpci_hp_intr");
/* Check to see if it was our interrupt */
if((controller->irq_flags & SA_SHIRQ) &&
!controller->ops->check_irq(controller->dev_id)) {
dbg("exited cpci_hp_intr, not our interrupt");
return;
}
/* Disable ENUM interrupt */
controller->ops->disable_irq();
/* Trigger processing by the event thread */
dbg("Signal event_semaphore");
up(&event_semaphore);
dbg("exited cpci_hp_intr");
}
/*
* According to PICMG 2.12 R2.0, section 6.3.2, upon
* initialization, the system driver shall clear the
* INS bits of the cold-inserted devices.
*/
static int
init_slots(void)
{
struct slot *slot;
struct list_head *tmp;
struct pci_dev* dev;
dbg("%s - enter", __FUNCTION__);
spin_lock(&list_lock);
if(!slots) {
spin_unlock(&list_lock);
return -1;
}
list_for_each(tmp, &slot_list) {
slot = list_entry(tmp, struct slot, slot_list);
dbg("%s - looking at slot %s",
__FUNCTION__, slot->hotplug_slot->name);
if(cpci_check_and_clear_ins(slot)) {
dbg("%s - cleared INS for slot %s",
__FUNCTION__, slot->hotplug_slot->name);
dev = pci_find_slot(slot->bus->number, PCI_DEVFN(slot->number, 0));
if(dev) {
if(update_adapter_status(slot->hotplug_slot, 1)) {
warn("failure to update adapter file");
}
if(update_latch_status(slot->hotplug_slot, 1)) {
warn("failure to update latch file");
}
slot->dev = dev;
} else {
err("%s - no driver attached to device in slot %s",
__FUNCTION__, slot->hotplug_slot->name);
}
}
}
spin_unlock(&list_lock);
dbg("%s - exit", __FUNCTION__);
return 0;
}
static int
check_slots(void)
{
struct slot *slot;
struct list_head *tmp;
int extracted;
int inserted;
spin_lock(&list_lock);
if(!slots) {
spin_unlock(&list_lock);
err("no slots registered, shutting down");
return -1;
}
extracted = inserted = 0;
list_for_each(tmp, &slot_list) {
slot = list_entry(tmp, struct slot, slot_list);
dbg("%s - looking at slot %s",
__FUNCTION__, slot->hotplug_slot->name);
if(cpci_check_and_clear_ins(slot)) {
u16 hs_csr;
/* Some broken hardware (e.g. PLX 9054AB) asserts ENUM# twice... */
if(slot->dev) {
warn("slot %s already inserted", slot->hotplug_slot->name);
inserted++;
continue;
}
/* Process insertion */
dbg("%s - slot %s inserted",
__FUNCTION__, slot->hotplug_slot->name);
/* GSM, debug */
hs_csr = cpci_get_hs_csr(slot);
dbg("%s - slot %s HS_CSR (1) = %04x",
__FUNCTION__, slot->hotplug_slot->name, hs_csr);
/* Configure device */
dbg("%s - configuring slot %s",
__FUNCTION__, slot->hotplug_slot->name);
if(cpci_configure_slot(slot)) {
err("%s - could not configure slot %s",
__FUNCTION__, slot->hotplug_slot->name);
continue;
}
dbg("%s - finished configuring slot %s",
__FUNCTION__, slot->hotplug_slot->name);
/* GSM, debug */
hs_csr = cpci_get_hs_csr(slot);
dbg("%s - slot %s HS_CSR (2) = %04x",
__FUNCTION__, slot->hotplug_slot->name, hs_csr);
if(update_latch_status(slot->hotplug_slot, 1)) {
warn("failure to update latch file");
}
if(update_adapter_status(slot->hotplug_slot, 1)) {
warn("failure to update adapter file");
}
cpci_led_off(slot);
/* GSM, debug */
hs_csr = cpci_get_hs_csr(slot);
dbg("%s - slot %s HS_CSR (3) = %04x",
__FUNCTION__, slot->hotplug_slot->name, hs_csr);
inserted++;
} else if(cpci_check_ext(slot)) {
u16 hs_csr;
/* Process extraction request */
dbg("%s - slot %s extracted",
__FUNCTION__, slot->hotplug_slot->name);
/* GSM, debug */
hs_csr = cpci_get_hs_csr(slot);
dbg("%s - slot %s HS_CSR = %04x",
__FUNCTION__, slot->hotplug_slot->name, hs_csr);
if(!slot->extracting) {
if(update_latch_status(slot->hotplug_slot, 0)) {
warn("failure to update latch file");
}
slot->extracting = 1;
}
extracted++;
}
}
spin_unlock(&list_lock);
if(inserted || extracted) {
return extracted;
}
else {
err("cannot find ENUM# source, shutting down");
return -1;
}
}
/* This is the interrupt mode worker thread body */
static int
event_thread(void *data)
{
int rc;
struct slot *slot;
struct list_head *tmp;
lock_kernel();
daemonize();
strcpy(current->comm, "cpci_hp_eventd");
unlock_kernel();
dbg("%s - event thread started", __FUNCTION__);
while(1) {
dbg("event thread sleeping");
down_interruptible(&event_semaphore);
dbg("event thread woken, thread_finished = %d",
thread_finished);
if(thread_finished || signal_pending(current))
break;
while(controller->ops->query_enum()) {
rc = check_slots();
if(rc > 0) {
/* Give userspace a chance to handle extraction */
set_current_state(TASK_INTERRUPTIBLE);
schedule_timeout(HZ / 2);
} else if(rc < 0) {
dbg("%s - error checking slots", __FUNCTION__);
thread_finished = 1;
break;
}
}
/* Check for someone yanking out a board */
list_for_each(tmp, &slot_list) {
slot = list_entry(tmp, struct slot, slot_list);
if(slot->extracting) {
/*
* Hmmm, we're likely hosed at this point, should we
* bother trying to tell the driver or not?
*/
err("card in slot %s was improperly removed",
slot->hotplug_slot->name);
if(update_adapter_status(slot->hotplug_slot, 0)) {
warn("failure to update adapter file");
}
slot->extracting = 0;
}
}
/* Re-enable ENUM# interrupt */
dbg("%s - re-enabling irq", __FUNCTION__);
controller->ops->enable_irq();
}
dbg("%s - event thread signals exit", __FUNCTION__);
up(&thread_exit);
return 0;
}
/* This is the polling mode worker thread body */
static int
poll_thread(void *data)
{
int rc;
struct slot *slot;
struct list_head *tmp;
lock_kernel();
daemonize();
strcpy(current->comm, "cpci_hp_polld");
unlock_kernel();
while(1) {
if(thread_finished || signal_pending(current))
break;
while(controller->ops->query_enum()) {
rc = check_slots();
if(rc > 0) {
/* Give userspace a chance to handle extraction */
set_current_state(TASK_INTERRUPTIBLE);
schedule_timeout(HZ / 2);
} else if(rc < 0) {
dbg("%s - error checking slots", __FUNCTION__);
thread_finished = 1;
break;
}
}
/* Check for someone yanking out a board */
list_for_each(tmp, &slot_list) {
slot = list_entry(tmp, struct slot, slot_list);
if(slot->extracting) {
/*
* Hmmm, we're likely hosed at this point, should we
* bother trying to tell the driver or not?
*/
err("card in slot %s was improperly removed",
slot->hotplug_slot->name);
if(update_adapter_status(slot->hotplug_slot, 0)) {
warn("failure to update adapter file");
}
slot->extracting = 0;
}
}
set_current_state(TASK_INTERRUPTIBLE);
schedule_timeout(HZ / 10);
}
dbg("poll thread signals exit");
up(&thread_exit);
return 0;
}
static int
cpci_start_thread(void)
{
int pid;
/* initialize our semaphores */
init_MUTEX_LOCKED(&event_semaphore);
init_MUTEX_LOCKED(&thread_exit);
thread_finished = 0;
if(controller->irq) {
pid = kernel_thread(event_thread, 0, 0);
} else {
pid = kernel_thread(poll_thread, 0, 0);
}
if(pid < 0) {
err("Can't start up our thread");
return -1;
}
dbg("Our thread pid = %d", pid);
return 0;
}
static void
cpci_stop_thread(void)
{
thread_finished = 1;
dbg("thread finish command given");
if(controller->irq) {
up(&event_semaphore);
}
dbg("wait for thread to exit");
down(&thread_exit);
}
int
cpci_hp_register_controller(struct cpci_hp_controller *new_controller)
{
int status = 0;
if(!controller) {
controller = new_controller;
if(controller->irq) {
if(request_irq(controller->irq,
cpci_hp_intr,
controller->irq_flags,
MY_NAME, controller->dev_id)) {
err("Can't get irq %d for the hotplug cPCI controller", controller->irq);
status = -ENODEV;
}
dbg("%s - acquired controller irq %d", __FUNCTION__,
controller->irq);
}
} else {
err("cPCI hotplug controller already registered");
status = -1;
}
return status;
}
int
cpci_hp_unregister_controller(struct cpci_hp_controller *old_controller)
{
int status = 0;
if(controller) {
if(!thread_finished) {
cpci_stop_thread();
}
if(controller->irq) {
free_irq(controller->irq, controller->dev_id);
}
controller = NULL;
} else {
status = -ENODEV;
}
return status;
}
int
cpci_hp_start(void)
{
static int first = 1;
int status;
dbg("%s - enter", __FUNCTION__);
if(!controller) {
return -ENODEV;
}
spin_lock(&list_lock);
if(!slots) {
spin_unlock(&list_lock);
return -ENODEV;
}
spin_unlock(&list_lock);
if(first) {
status = init_slots();
if(status) {
return status;
}
first = 0;
}
status = cpci_start_thread();
if(status) {
return status;
}
dbg("%s - thread started", __FUNCTION__);
if(controller->irq) {
/* Start enum interrupt processing */
dbg("%s - enabling irq", __FUNCTION__);
controller->ops->enable_irq();
}
dbg("%s - exit", __FUNCTION__);
return 0;
}
int
cpci_hp_stop(void)
{
if(!controller) {
return -ENODEV;
}
if(controller->irq) {
/* Stop enum interrupt processing */
dbg("%s - disabling irq", __FUNCTION__);
controller->ops->disable_irq();
}
cpci_stop_thread();
return 0;
}
static void __exit
cleanup_slots(void)
{
struct list_head *tmp;
struct slot *slot;
/*
* Unregister all of our slots with the pci_hotplug subsystem,
* and free up all memory that we had allocated.
*/
spin_lock(&list_lock);
if(!slots) {
goto null_cleanup;
}
list_for_each(tmp, &slot_list) {
slot = list_entry(tmp, struct slot, slot_list);
list_del(&slot->slot_list);
pci_hp_deregister(slot->hotplug_slot);
kfree(slot->hotplug_slot->info);
kfree(slot->hotplug_slot->name);
kfree(slot->hotplug_slot);
kfree(slot);
}
null_cleanup:
spin_unlock(&list_lock);
return;
}
static int __init
cpci_hotplug_init(void)
{
spin_lock_init(&list_lock);
info(DRIVER_DESC " version: " DRIVER_VERSION);
return 0;
}
static void __exit
cpci_hotplug_exit(void)
{
/*
* Clean everything up.
*/
cleanup_slots();
}
module_init(cpci_hotplug_init);
module_exit(cpci_hotplug_exit);
MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_LICENSE("GPL");
MODULE_PARM(cpci_debug, "i");
MODULE_PARM_DESC(cpci_debug, "Debugging mode");
EXPORT_SYMBOL_GPL(cpci_hp_register_controller);
EXPORT_SYMBOL_GPL(cpci_hp_unregister_controller);
EXPORT_SYMBOL_GPL(cpci_hp_register_bus);
EXPORT_SYMBOL_GPL(cpci_hp_unregister_bus);
EXPORT_SYMBOL_GPL(cpci_find_slot);
EXPORT_SYMBOL_GPL(cpci_hp_start);
EXPORT_SYMBOL_GPL(cpci_hp_stop);
/*
* CompactPCI Hot Plug Driver PCI functions
*
* Copyright (c) 2002 by SOMA Networks, Inc.
*
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or (at
* your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
* NON INFRINGEMENT. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* Send feedback to <scottm@somanetworks.com>
*/
#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/pci.h>
#include <linux/proc_fs.h>
#include "pci_hotplug.h"
#include "cpci_hotplug.h"
#if !defined(CONFIG_HOTPLUG_CPCI_MODULE)
#define MY_NAME "cpci_hotplug"
#else
#define MY_NAME THIS_MODULE->name
#endif
extern int cpci_debug;
#define dbg(format, arg...) \
do { \
if(cpci_debug) \
printk (KERN_DEBUG "%s: " format "\n", \
MY_NAME , ## arg); \
} while(0)
#define err(format, arg...) printk(KERN_ERR "%s: " format "\n", MY_NAME , ## arg)
#define info(format, arg...) printk(KERN_INFO "%s: " format "\n", MY_NAME , ## arg)
#define warn(format, arg...) printk(KERN_WARNING "%s: " format "\n", MY_NAME , ## arg)
#define ROUND_UP(x, a) (((x) + (a) - 1) & ~((a) - 1))
u8 cpci_get_attention_status(struct slot* slot)
{
int hs_cap;
u16 hs_csr;
hs_cap = pci_bus_find_capability(slot->bus,
slot->devfn,
PCI_CAP_ID_CHSWP);
if(!hs_cap) {
return 0;
}
if(pci_bus_read_config_word(slot->bus,
slot->devfn,
hs_cap + 2,
&hs_csr)) {
return 0;
}
return hs_csr & 0x0008 ? 1 : 0;
}
int cpci_set_attention_status(struct slot* slot, int status)
{
int hs_cap;
u16 hs_csr;
hs_cap = pci_bus_find_capability(slot->bus,
slot->devfn,
PCI_CAP_ID_CHSWP);
if(!hs_cap) {
return 0;
}
if(pci_bus_read_config_word(slot->bus,
slot->devfn,
hs_cap + 2,
&hs_csr)) {
return 0;
}
if(status) {
hs_csr |= HS_CSR_LOO;
} else {
hs_csr &= ~HS_CSR_LOO;
}
if(pci_bus_write_config_word(slot->bus,
slot->devfn,
hs_cap + 2,
hs_csr)) {
return 0;
}
return 1;
}
u16 cpci_get_hs_csr(struct slot* slot)
{
int hs_cap;
u16 hs_csr;
hs_cap = pci_bus_find_capability(slot->bus,
slot->devfn,
PCI_CAP_ID_CHSWP);
if(!hs_cap) {
return 0xFFFF;
}
if(pci_bus_read_config_word(slot->bus,
slot->devfn,
hs_cap + 2,
&hs_csr)) {
return 0xFFFF;
}
return hs_csr;
}
u16 cpci_set_hs_csr(struct slot* slot, u16 hs_csr)
{
int hs_cap;
u16 new_hs_csr;
hs_cap = pci_bus_find_capability(slot->bus,
slot->devfn,
PCI_CAP_ID_CHSWP);
if(!hs_cap) {
return 0xFFFF;
}
/* Write out the new value */
if(pci_bus_write_config_word(slot->bus,
slot->devfn,
hs_cap + 2,
hs_csr)) {
return 0xFFFF;
}
/* Read back what we just wrote out */
if(pci_bus_read_config_word(slot->bus,
slot->devfn,
hs_cap + 2,
&new_hs_csr)) {
return 0xFFFF;
}
return new_hs_csr;
}
int cpci_check_and_clear_ins(struct slot* slot)
{
int hs_cap;
u16 hs_csr;
int ins = 0;
hs_cap = pci_bus_find_capability(slot->bus,
slot->devfn,
PCI_CAP_ID_CHSWP);
if(!hs_cap) {
return 0;
}
if(pci_bus_read_config_word(slot->bus,
slot->devfn,
hs_cap + 2,
&hs_csr)) {
return 0;
}
if(hs_csr & HS_CSR_INS) {
/* Clear INS (by setting it) */
if(pci_bus_write_config_word(slot->bus,
slot->devfn,
hs_cap + 2,
hs_csr)) {
ins = 0;
}
ins = 1;
}
return ins;
}
int cpci_check_ext(struct slot* slot)
{
int hs_cap;
u16 hs_csr;
int ext = 0;
hs_cap = pci_bus_find_capability(slot->bus,
slot->devfn,
PCI_CAP_ID_CHSWP);
if(!hs_cap) {
return 0;
}
if(pci_bus_read_config_word(slot->bus,
slot->devfn,
hs_cap + 2,
&hs_csr)) {
return 0;
}
if(hs_csr & HS_CSR_EXT) {
ext = 1;
}
return ext;
}
int cpci_clear_ext(struct slot* slot)
{
int hs_cap;
u16 hs_csr;
hs_cap = pci_bus_find_capability(slot->bus,
slot->devfn,
PCI_CAP_ID_CHSWP);
if(!hs_cap) {
return -ENODEV;
}
if(pci_bus_read_config_word(slot->bus,
slot->devfn,
hs_cap + 2,
&hs_csr)) {
return -ENODEV;
}
if(hs_csr & HS_CSR_EXT) {
/* Clear EXT (by setting it) */
if(pci_bus_write_config_word(slot->bus,
slot->devfn,
hs_cap + 2,
hs_csr)) {
return -ENODEV;
}
}
return 0;
}
int cpci_led_on(struct slot* slot)
{
int hs_cap;
u16 hs_csr;
hs_cap = pci_bus_find_capability(slot->bus,
slot->devfn,
PCI_CAP_ID_CHSWP);
if(!hs_cap) {
return -ENODEV;
}
if(pci_bus_read_config_word(slot->bus,
slot->devfn,
hs_cap + 2,
&hs_csr)) {
return -ENODEV;
}
if((hs_csr & HS_CSR_LOO) != HS_CSR_LOO) {
/* Set LOO */
hs_csr |= HS_CSR_LOO;
if(pci_bus_write_config_word(slot->bus,
slot->devfn,
hs_cap + 2,
hs_csr)) {
err("Could not set LOO for slot %s",
slot->hotplug_slot->name);
return -ENODEV;
}
}
return 0;
}
int cpci_led_off(struct slot* slot)
{
int hs_cap;
u16 hs_csr;
hs_cap = pci_bus_find_capability(slot->bus,
slot->devfn,
PCI_CAP_ID_CHSWP);
if(!hs_cap) {
return -ENODEV;
}
if(pci_bus_read_config_word(slot->bus,
slot->devfn,
hs_cap + 2,
&hs_csr)) {
return -ENODEV;
}
if(hs_csr & HS_CSR_LOO) {
/* Clear LOO */
hs_csr &= ~HS_CSR_LOO;
if(pci_bus_write_config_word(slot->bus,
slot->devfn,
hs_cap + 2,
hs_csr)) {
err("Could not clear LOO for slot %s",
slot->hotplug_slot->name);
return -ENODEV;
}
}
return 0;
}
/*
* Device configuration functions
*/
static int cpci_configure_dev(struct pci_bus *bus, struct pci_dev *dev)
{
u8 irq_pin;
int r;
dbg("%s - enter", __FUNCTION__);
/* NOTE: device already setup from prior scan */
/* FIXME: How would we know if we need to enable the expansion ROM? */
pci_write_config_word(dev, PCI_ROM_ADDRESS, 0x00L);
/* Assign resources */
dbg("assigning resources for %02x:%02x.%x",
dev->bus->number, PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn));
for (r = 0; r < 6; r++) {
struct resource *res = dev->resource + r;
if(res->flags)
pci_assign_resource(dev, r);
}
dbg("finished assigning resources for %02x:%02x.%x",
dev->bus->number, PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn));
/* Does this function have an interrupt at all? */
dbg("checking for function interrupt");
pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &irq_pin);
if(irq_pin) {
dbg("function uses interrupt pin %d", irq_pin);
}
/*
* Need to explicitly set irq field to 0 so that it'll get assigned
* by the pcibios platform dependant code called by pci_enable_device.
*/
dev->irq = 0;
dbg("enabling device");
pci_enable_device(dev); /* XXX check return */
dbg("now dev->irq = %d", dev->irq);
if(irq_pin && dev->irq) {
pci_write_config_byte(dev, PCI_INTERRUPT_LINE, dev->irq);
}
/* Can't use pci_insert_device at the moment, do it manually for now */
pci_proc_attach_device(dev);
dbg("notifying drivers");
//pci_announce_device_to_drivers(dev);
dbg("%s - exit", __FUNCTION__);
return 0;
}
static int cpci_configure_bridge(struct pci_bus* bus, struct pci_dev* dev)
{
int rc;
struct pci_bus* child;
struct resource* r;
u8 max, n;
u16 command;
dbg("%s - enter", __FUNCTION__);
/* Do basic bridge initialization */
rc = pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x40);
if(rc) {
printk(KERN_ERR "%s - write of PCI_LATENCY_TIMER failed\n", __FUNCTION__);
}
rc = pci_write_config_byte(dev, PCI_SEC_LATENCY_TIMER, 0x40);
if(rc) {
printk(KERN_ERR "%s - write of PCI_SEC_LATENCY_TIMER failed\n", __FUNCTION__);
}
rc = pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, L1_CACHE_BYTES / 4);
if(rc) {
printk(KERN_ERR "%s - write of PCI_CACHE_LINE_SIZE failed\n", __FUNCTION__);
}
/*
* Set parent bridge's subordinate field so that configuration space
* access will work in pci_scan_bridge and friends.
*/
max = pci_max_busnr();
bus->subordinate = max + 1;
pci_write_config_byte(bus->self, PCI_SUBORDINATE_BUS, max + 1);
/* Scan behind bridge */
n = pci_scan_bridge(bus, dev, max, 2);
child = pci_find_bus(max + 1);
#ifdef CONFIG_PROC_FS
pci_proc_attach_bus(child);
#endif
/*
* Update parent bridge's subordinate field if there were more bridges
* behind the bridge that was scanned.
*/
if(n > max) {
bus->subordinate = n;
pci_write_config_byte(bus->self, PCI_SUBORDINATE_BUS, n);
}
/*
* Update the bridge resources of the bridge to accommodate devices
* behind it.
*/
pbus_size_bridges(child);
pbus_assign_resources(child);
/* Enable resource mapping via command register */
command = PCI_COMMAND_MASTER | PCI_COMMAND_INVALIDATE | PCI_COMMAND_PARITY | PCI_COMMAND_SERR;
r = child->resource[0];
if(r && r->start) {
command |= PCI_COMMAND_IO;
}
r = child->resource[1];
if(r && r->start) {
command |= PCI_COMMAND_MEMORY;
}
r = child->resource[2];
if(r && r->start) {
command |= PCI_COMMAND_MEMORY;
}
rc = pci_write_config_word(dev, PCI_COMMAND, command);
if(rc) {
err("Error setting command register");
return rc;
}
/* Set bridge control register */
command = PCI_BRIDGE_CTL_PARITY | PCI_BRIDGE_CTL_SERR | PCI_BRIDGE_CTL_NO_ISA;
rc = pci_write_config_word(dev, PCI_BRIDGE_CONTROL, command);
if(rc) {
err("Error setting bridge control register");
return rc;
}
dbg("%s - exit", __FUNCTION__);
return 0;
}
static int configure_visit_pci_dev(struct pci_dev_wrapped *wrapped_dev,
struct pci_bus_wrapped *wrapped_bus)
{
int rc;
struct pci_dev *dev = wrapped_dev->dev;
struct pci_bus *bus = wrapped_bus->bus;
struct slot* slot;
dbg("%s - enter", __FUNCTION__);
/*
* We need to fix up the hotplug representation with the Linux
* representation.
*/
slot = cpci_find_slot(dev->bus, dev->devfn);
if(slot) {
slot->dev = dev;
}
/* If it's a bridge, scan behind it for devices */
if(dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) {
rc = cpci_configure_bridge(bus, dev);
if(rc)
return rc;
}
/* Actually configure device */
if(dev) {
rc = cpci_configure_dev(bus, dev);
if(rc)
return rc;
}
dbg("%s - exit", __FUNCTION__);
return 0;
}
static int unconfigure_visit_pci_dev_phase1(struct pci_dev_wrapped *wrapped_dev,
struct pci_bus_wrapped *wrapped_bus)
{
struct pci_dev *dev = wrapped_dev->dev;
dbg("%s - enter", __FUNCTION__);
dbg("attempting removal of driver for device %02x:%02x.%x",
dev->bus->number, PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn));
/* Now, remove the Linux Driver representation */
if(dev->driver) {
dbg("device is attached to a driver");
if(dev->driver->remove) {
dev->driver->remove(dev);
dbg("driver was removed");
}
dev->driver = NULL;
}
dbg("%s - exit", __FUNCTION__);
return pci_is_dev_in_use(dev);
}
static int unconfigure_visit_pci_dev_phase2(struct pci_dev_wrapped *wrapped_dev,
struct pci_bus_wrapped *wrapped_bus)
{
struct pci_dev *dev = wrapped_dev->dev;
struct slot* slot;
dbg("%s - enter", __FUNCTION__);
if(!dev)
return -ENODEV;
/* Remove the Linux representation */
if(pci_remove_device_safe(dev) == 0) {
kfree(dev);
} else {
err("Could not remove device\n");
return -1;
}
/*
* Now remove the hotplug representation.
*/
slot = cpci_find_slot(dev->bus, dev->devfn);
if(slot) {
slot->dev = NULL;
} else {
dbg("No hotplug representation for %02x:%02x.%x",
dev->bus->number, PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn));
}
dbg("%s - exit", __FUNCTION__);
return 0;
}
static int unconfigure_visit_pci_bus_phase2(struct pci_bus_wrapped *wrapped_bus,
struct pci_dev_wrapped *wrapped_dev)
{
struct pci_bus *bus = wrapped_bus->bus;
struct pci_bus *parent = bus->self->bus;
dbg("%s - enter", __FUNCTION__);
/* The cleanup code for proc entries regarding buses should be in the kernel... */
if(bus->procdir)
dbg("detach_pci_bus %s", bus->procdir->name);
pci_proc_detach_bus(bus);
/* The cleanup code should live in the kernel... */
bus->self->subordinate = NULL;
/* unlink from parent bus */
list_del(&bus->node);
/* Now, remove */
if(bus)
kfree(bus);
/* Update parent's subordinate field */
if(parent) {
u8 n = pci_bus_max_busnr(parent);
if(n < parent->subordinate) {
parent->subordinate = n;
pci_write_config_byte(parent->self, PCI_SUBORDINATE_BUS, n);
}
}
dbg("%s - exit", __FUNCTION__);
return 0;
}
static struct pci_visit configure_functions = {
visit_pci_dev:configure_visit_pci_dev,
};
static struct pci_visit unconfigure_functions_phase1 = {
post_visit_pci_dev:unconfigure_visit_pci_dev_phase1
};
static struct pci_visit unconfigure_functions_phase2 = {
post_visit_pci_bus:unconfigure_visit_pci_bus_phase2,
post_visit_pci_dev:unconfigure_visit_pci_dev_phase2
};
int cpci_configure_slot(struct slot* slot)
{
int rc = 0;
dbg("%s - enter", __FUNCTION__);
if(slot->dev == NULL) {
dbg("pci_dev null, finding %02x:%02x:%x",
slot->bus->number, PCI_SLOT(slot->devfn), PCI_FUNC(slot->devfn));
slot->dev = pci_find_slot(slot->bus->number, slot->devfn);
}
/* Still NULL? Well then scan for it! */
if(slot->dev == NULL) {
struct pci_dev dev0;
dbg("pci_dev still null");
memset(&dev0, 0, sizeof (struct pci_dev));
dev0.bus = slot->bus;
dev0.devfn = slot->devfn;
dev0.sysdata = slot->bus->self->sysdata;
/*
* This will generate pci_dev structures for all functions, but
* we will only call this case when lookup fails.
*/
slot->dev = pci_scan_slot(&dev0);
if(slot->dev == NULL) {
err("Could not find PCI device for slot %02x", slot->number);
return 0;
}
}
dbg("slot->dev = %p", slot->dev);
if(slot->dev) {
struct pci_dev *dev;
struct pci_dev_wrapped wrapped_dev;
struct pci_bus_wrapped wrapped_bus;
int i;
memset(&wrapped_dev, 0, sizeof (struct pci_dev_wrapped));
memset(&wrapped_bus, 0, sizeof (struct pci_bus_wrapped));
for (i = 0; i < 8; i++) {
dev = pci_find_slot(slot->bus->number,
PCI_DEVFN(PCI_SLOT(slot->dev->devfn), i));
if(!dev)
continue;
wrapped_dev.dev = dev;
wrapped_bus.bus = slot->dev->bus;
rc = pci_visit_dev(&configure_functions, &wrapped_dev, &wrapped_bus);
}
}
dbg("%s - exit, rc = %d", __FUNCTION__, rc);
return rc;
}
int cpci_unconfigure_slot(struct slot* slot)
{
int rc = 0;
int i;
struct pci_dev_wrapped wrapped_dev;
struct pci_bus_wrapped wrapped_bus;
struct pci_dev *dev;
dbg("%s - enter", __FUNCTION__);
if(!slot->dev) {
err("No device for slot %02x\n", slot->number);
return -ENODEV;
}
memset(&wrapped_dev, 0, sizeof (struct pci_dev_wrapped));
memset(&wrapped_bus, 0, sizeof (struct pci_bus_wrapped));
for (i = 0; i < 8; i++) {
dev = pci_find_slot(slot->bus->number,
PCI_DEVFN(PCI_SLOT(slot->devfn), i));
if(dev) {
wrapped_dev.dev = dev;
wrapped_bus.bus = dev->bus;
dbg("%s - unconfigure phase 1", __FUNCTION__);
rc = pci_visit_dev(&unconfigure_functions_phase1,
&wrapped_dev, &wrapped_bus);
if(rc) {
break;
}
dbg("%s - unconfigure phase 2", __FUNCTION__);
rc = pci_visit_dev(&unconfigure_functions_phase2,
&wrapped_dev, &wrapped_bus);
if(rc)
break;
}
}
dbg("%s - exit, rc = %d", __FUNCTION__, rc);
return rc;
}
/*
* cpcihp_generic.c
*
* Generic port I/O CompactPCI driver
*
* Copyright 2002 SOMA Networks, Inc.
* Copyright 2001 Intel San Luis Obispo
* Copyright 2000,2001 MontaVista Software Inc.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
* THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 675 Mass Ave, Cambridge, MA 02139, USA.
*
* This generic CompactPCI hotplug driver should allow using the PCI hotplug
* mechanism on any CompactPCI board that exposes the #ENUM signal as a bit
* in a system register that can be read through standard port I/O.
*
* Send feedback to <scottm@somanetworks.com>
*/
#include <linux/config.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/errno.h>
#include <linux/pci.h>
#include "cpci_hotplug.h"
#define DRIVER_VERSION "0.1"
#define DRIVER_AUTHOR "Scott Murray <scottm@somanetworks.com>"
#define DRIVER_DESC "Generic port I/O CompactPCI Hot Plug Driver"
#if !defined(CONFIG_HOTPLUG_CPCI_GENERIC_MODULE)
#define MY_NAME "cpcihp_generic"
#else
#define MY_NAME THIS_MODULE->name
#endif
#define dbg(format, arg...) \
do { \
if(debug) \
printk (KERN_DEBUG "%s: " format "\n", \
MY_NAME , ## arg); \
} while(0)
#define err(format, arg...) printk(KERN_ERR "%s: " format "\n", MY_NAME , ## arg)
#define info(format, arg...) printk(KERN_INFO "%s: " format "\n", MY_NAME , ## arg)
#define warn(format, arg...) printk(KERN_WARNING "%s: " format "\n", MY_NAME , ## arg)
/* local variables */
static int debug;
static char* bridge;
static u8 bridge_busnr;
static u8 bridge_slot;
static struct pci_bus *bus;
static u8 first_slot;
static u8 last_slot;
static u16 port;
static unsigned int enum_bit;
static u8 enum_mask;
static struct cpci_hp_controller_ops generic_hpc_ops;
static struct cpci_hp_controller generic_hpc;
/* The following allows configuring the driver when it's compiled into the kernel */
#ifndef MODULE
static int __init cpcihp_generic_setup(char* str)
{
char* p;
unsigned long tmp;
if(!str)
return -EINVAL;
bridge = str;
p = strchr(str, ',');
str = p + 1;
if(!(p && *str && *p == ','))
goto setup_error;
tmp = simple_strtoul(str, &p, 0);
if(p == str || tmp > 0xff) {
err("hotplug bus first slot number out of range");
goto setup_error;
}
first_slot = (u8) tmp;
str = p + 1;
if(!(*str && *p == ','))
return -EINVAL;
tmp = simple_strtoul(str, &p, 0);
if(p == str || tmp > 0xff) {
err("hotplug bus last slot number out of range");
goto setup_error;
}
last_slot = (u8) tmp;
str = p + 1;
if(!(*str && *p == ','))
goto setup_error;
tmp = simple_strtoul(str, &p, 0);
if(p == str || tmp > 0xffff) {
err("port number out of range");
goto setup_error;
}
port = (u16) tmp;
str = p + 1;
if(!(*str && *p == ','))
goto setup_error;
tmp = simple_strtoul(str, &p, 0);
if(p == str) {
err("invalid #ENUM bit number");
goto setup_error;
}
enum_bit = (u8) tmp;
str = p + 1;
if(*str && *p == ',') {
tmp = simple_strtoul(str, &p, 0);
if(p != str)
debug = (int) tmp;
}
return 0;
setup_error:
bridge = NULL;
return -EINVAL;
}
__setup("cpcihp_generic=", cpcihp_generic_setup);
#endif
static int __init validate_parameters(void)
{
char* str;
char* p;
unsigned long tmp;
if(!bridge) {
info("not configured, disabling.");
return 1;
}
str = bridge;
if(!*str)
return -EINVAL;
tmp = simple_strtoul(str, &p, 16);
if(p == str || tmp > 0xff) {
err("Invalid hotplug bus bridge device bus number");
return -EINVAL;
}
bridge_busnr = (u8) tmp;
dbg("bridge_busnr = 0x%02x", bridge_busnr);
if(*p != ':') {
err("Invalid hotplug bus bridge device");
return -EINVAL;
}
str = p + 1;
tmp = simple_strtoul(str, &p, 16);
if(p == str || tmp > 0x1f) {
err("Invalid hotplug bus bridge device slot number");
return -EINVAL;
}
bridge_slot = (u8) tmp;
dbg("bridge_slot = 0x%02x", bridge_slot);
dbg("first_slot = 0x%02x", first_slot);
dbg("last_slot = 0x%02x", last_slot);
if(!(first_slot && last_slot)) {
err("Need to specify first_slot and last_slot");
return -EINVAL;
}
if(last_slot < first_slot) {
err("first_slot must be less than last_slot");
return -EINVAL;
}
dbg("port = 0x%04x", port);
dbg("enum_bit = 0x%02x", enum_bit);
if(enum_bit > 7) {
err("Invalid #ENUM bit");
return -EINVAL;
}
enum_mask = 1 << enum_bit;
return 0;
}
static int query_enum(void)
{
u8 value;
value = inb_p(port);
return ((value & enum_mask) == enum_mask);
}
static int __init cpcihp_generic_init(void)
{
int status;
struct resource* r;
struct pci_dev* dev;
info(DRIVER_DESC " version: " DRIVER_VERSION);
status = validate_parameters();
if(status != 0)
return status;
r = request_region(port, 1, "#ENUM hotswap signal register");
if(!r)
return -EBUSY;
dev = pci_find_slot(bridge_busnr, PCI_DEVFN(bridge_slot, 0));
if(!dev || dev->hdr_type != PCI_HEADER_TYPE_BRIDGE) {
err("Invalid bridge device %s", bridge);
return -EINVAL;
}
bus = dev->subordinate;
memset(&generic_hpc, 0, sizeof (struct cpci_hp_controller));
generic_hpc_ops.query_enum = query_enum;
generic_hpc.ops = &generic_hpc_ops;
status = cpci_hp_register_controller(&generic_hpc);
if(status != 0) {
err("Could not register cPCI hotplug controller");
return -ENODEV;
}
dbg("registered controller");
status = cpci_hp_register_bus(bus, first_slot, last_slot);
if(status != 0) {
err("Could not register cPCI hotplug bus");
goto init_bus_register_error;
}
dbg("registered bus");
status = cpci_hp_start();
if(status != 0) {
err("Could not started cPCI hotplug system");
goto init_start_error;
}
dbg("started cpci hp system");
return 0;
init_start_error:
cpci_hp_unregister_bus(bus);
init_bus_register_error:
cpci_hp_unregister_controller(&generic_hpc);
err("status = %d", status);
return status;
}
static void __exit cpcihp_generic_exit(void)
{
cpci_hp_stop();
cpci_hp_unregister_bus(bus);
cpci_hp_unregister_controller(&generic_hpc);
release_region(port, 1);
}
module_init(cpcihp_generic_init);
module_exit(cpcihp_generic_exit);
MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_LICENSE("GPL");
MODULE_PARM(debug, "i");
MODULE_PARM_DESC(debug, "Debugging mode enabled or not");
MODULE_PARM(bridge, "s");
MODULE_PARM_DESC(bridge, "Hotswap bus bridge device, <bus>:<slot> (bus and slot are in hexadecimal)");
MODULE_PARM(first_slot, "b");
MODULE_PARM_DESC(first_slot, "Hotswap bus first slot number");
MODULE_PARM(last_slot, "b");
MODULE_PARM_DESC(last_slot, "Hotswap bus last slot number");
MODULE_PARM(port, "h");
MODULE_PARM_DESC(port, "#ENUM signal I/O port");
MODULE_PARM(enum_bit, "i");
MODULE_PARM_DESC(enum_bit, "#ENUM signal bit (0-7)");
/*
* cpcihp_zt5550.c
*
* Intel/Ziatech ZT5550 CompactPCI Host Controller driver
*
* Copyright 2002 SOMA Networks, Inc.
* Copyright 2001 Intel San Luis Obispo
* Copyright 2000,2001 MontaVista Software Inc.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
* THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 675 Mass Ave, Cambridge, MA 02139, USA.
*
* Send feedback to <scottm@somanetworks.com>
*/
#include <linux/config.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/errno.h>
#include <linux/pci.h>
#include "cpci_hotplug.h"
#include "cpcihp_zt5550.h"
#define DRIVER_VERSION "0.2"
#define DRIVER_AUTHOR "Scott Murray <scottm@somanetworks.com>"
#define DRIVER_DESC "ZT5550 CompactPCI Hot Plug Driver"
#if !defined(CONFIG_HOTPLUG_PCI_CPCI_ZT5550_MODULE)
#define MY_NAME "cpcihp_zt5550"
#else
#define MY_NAME THIS_MODULE->name
#endif
#define dbg(format, arg...) \
do { \
if(debug) \
printk (KERN_DEBUG "%s: " format "\n", \
MY_NAME , ## arg); \
} while(0)
#define err(format, arg...) printk(KERN_ERR "%s: " format "\n", MY_NAME , ## arg)
#define info(format, arg...) printk(KERN_INFO "%s: " format "\n", MY_NAME , ## arg)
#define warn(format, arg...) printk(KERN_WARNING "%s: " format "\n", MY_NAME , ## arg)
/* local variables */
static int debug;
static int poll;
static struct cpci_hp_controller_ops zt5550_hpc_ops;
static struct cpci_hp_controller zt5550_hpc;
/* Primary cPCI bus bridge device */
static struct pci_dev *bus0_dev;
static struct pci_bus *bus0;
/* Host controller device */
static struct pci_dev *hc_dev;
/* Host controller register addresses */
static void *hc_registers;
static void *csr_hc_index;
static void *csr_hc_data;
static void *csr_int_status;
static void *csr_int_mask;
static int zt5550_hc_config(struct pci_dev *pdev)
{
/* Since we know that no boards exist with two HC chips, treat it as an error */
if(hc_dev) {
err("too many host controller devices?");
return -EBUSY;
}
hc_dev = pdev;
dbg("hc_dev = %p", hc_dev);
dbg("pci resource start %lx", pci_resource_start(hc_dev, 1));
dbg("pci resource len %lx", pci_resource_len(hc_dev, 1));
if(!request_mem_region(pci_resource_start(hc_dev, 1),
pci_resource_len(hc_dev, 1), MY_NAME)) {
err("cannot reserve MMIO region");
return -ENOMEM;
}
hc_registers =
ioremap(pci_resource_start(hc_dev, 1), pci_resource_len(hc_dev, 1));
if(!hc_registers) {
err("cannot remap MMIO region %lx @ %lx",
pci_resource_len(hc_dev, 1), pci_resource_start(hc_dev, 1));
release_mem_region(pci_resource_start(hc_dev, 1),
pci_resource_len(hc_dev, 1));
return -ENODEV;
}
csr_hc_index = hc_registers + CSR_HCINDEX;
csr_hc_data = hc_registers + CSR_HCDATA;
csr_int_status = hc_registers + CSR_INTSTAT;
csr_int_mask = hc_registers + CSR_INTMASK;
/*
* Disable host control, fault and serial interrupts
*/
dbg("disabling host control, fault and serial interrupts");
writeb((u8) HC_INT_MASK_REG, csr_hc_index);
writeb((u8) ALL_INDEXED_INTS_MASK, csr_hc_data);
dbg("disabled host control, fault and serial interrupts");
/*
* Disable timer0, timer1 and ENUM interrupts
*/
dbg("disabling timer0, timer1 and ENUM interrupts");
writeb((u8) ALL_DIRECT_INTS_MASK, csr_int_mask);
dbg("disabled timer0, timer1 and ENUM interrupts");
return 0;
}
static int zt5550_hc_cleanup(void)
{
if(!hc_dev)
return -ENODEV;
release_mem_region(pci_resource_start(hc_dev, 1),
pci_resource_len(hc_dev, 1));
return 0;
}
static int zt5550_hc_query_enum(void)
{
u8 value;
value = inb_p(ENUM_PORT);
return ((value & ENUM_MASK) == ENUM_MASK);
}
static int zt5550_hc_check_irq(void *dev_id)
{
int ret;
u8 reg;
ret = 0;
if(dev_id == zt5550_hpc.dev_id) {
reg = readb(csr_int_status);
if(reg)
ret = 1;
}
return ret;
}
static int zt5550_hc_enable_irq(void)
{
u8 reg;
if(hc_dev == NULL) {
return -ENODEV;
}
reg = readb(csr_int_mask);
reg = reg & ~ENUM_INT_MASK;
writeb(reg, csr_int_mask);
return 0;
}
int zt5550_hc_disable_irq(void)
{
u8 reg;
if(hc_dev == NULL) {
return -ENODEV;
}
reg = readb(csr_int_mask);
reg = reg | ENUM_INT_MASK;
writeb(reg, csr_int_mask);
return 0;
}
static int __devinit zt5550_hc_init_one (struct pci_dev *pdev,
const struct pci_device_id *ent)
{
int status;
status = zt5550_hc_config(pdev);
if(status != 0) {
return status;
}
dbg("returned from zt5550_hc_config");
memset(&zt5550_hpc, 0, sizeof (struct cpci_hp_controller));
zt5550_hpc_ops.query_enum = zt5550_hc_query_enum;
zt5550_hpc.ops = &zt5550_hpc_ops;
if(!poll) {
zt5550_hpc.irq = hc_dev->irq;
zt5550_hpc.irq_flags = SA_SHIRQ;
zt5550_hpc.dev_id = hc_dev;
zt5550_hpc_ops.enable_irq = zt5550_hc_enable_irq;
zt5550_hpc_ops.disable_irq = zt5550_hc_disable_irq;
zt5550_hpc_ops.check_irq = zt5550_hc_check_irq;
} else {
info("using ENUM# polling mode");
}
status = cpci_hp_register_controller(&zt5550_hpc);
if(status != 0) {
err("could not register cPCI hotplug controller");
goto init_hc_error;
}
dbg("registered controller");
/* Look for first device matching cPCI bus's bridge vendor and device IDs */
if(!(bus0_dev = pci_find_device(PCI_VENDOR_ID_DEC,
PCI_DEVICE_ID_DEC_21154, NULL))) {
status = -ENODEV;
goto init_register_error;
}
bus0 = bus0_dev->subordinate;
status = cpci_hp_register_bus(bus0, 0x0a, 0x0f);
if(status != 0) {
err("could not register cPCI hotplug bus");
goto init_register_error;
}
dbg("registered bus");
status = cpci_hp_start();
if(status != 0) {
err("could not started cPCI hotplug system");
cpci_hp_unregister_bus(bus0);
goto init_register_error;
}
dbg("started cpci hp system");
return 0;
init_register_error:
cpci_hp_unregister_controller(&zt5550_hpc);
init_hc_error:
err("status = %d", status);
zt5550_hc_cleanup();
return status;
}
static void __devexit zt5550_hc_remove_one(struct pci_dev *pdev)
{
cpci_hp_stop();
cpci_hp_unregister_bus(bus0);
cpci_hp_unregister_controller(&zt5550_hpc);
zt5550_hc_cleanup();
}
static struct pci_device_id zt5550_hc_pci_tbl[] __devinitdata = {
{ PCI_VENDOR_ID_ZIATECH, PCI_DEVICE_ID_ZIATECH_5550_HC, PCI_ANY_ID, PCI_ANY_ID, },
{ 0, }
};
MODULE_DEVICE_TABLE(pci, zt5550_hc_pci_tbl);
static struct pci_driver zt5550_hc_driver = {
.name = "zt5550_hc",
.id_table = zt5550_hc_pci_tbl,
.probe = zt5550_hc_init_one,
.remove = __devexit_p(zt5550_hc_remove_one),
};
static int __init zt5550_init(void)
{
struct resource* r;
info(DRIVER_DESC " version: " DRIVER_VERSION);
r = request_region(ENUM_PORT, 1, "#ENUM hotswap signal register");
if(!r)
return -EBUSY;
return pci_module_init(&zt5550_hc_driver);
}
static void __exit
zt5550_exit(void)
{
pci_unregister_driver(&zt5550_hc_driver);
release_region(ENUM_PORT, 1);
}
module_init(zt5550_init);
module_exit(zt5550_exit);
MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_LICENSE("GPL");
MODULE_PARM(debug, "i");
MODULE_PARM_DESC(debug, "Debugging mode enabled or not");
MODULE_PARM(poll, "i");
MODULE_PARM_DESC(poll, "#ENUM polling mode enabled or not");
/*
* cpcihp_zt5550.h
*
* Intel/Ziatech ZT5550 CompactPCI Host Controller driver definitions
*
* Copyright 2002 SOMA Networks, Inc.
* Copyright 2001 Intel San Luis Obispo
* Copyright 2000,2001 MontaVista Software Inc.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
* THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 675 Mass Ave, Cambridge, MA 02139, USA.
*
* Send feedback to <scottm@somanetworks.com>
*/
#ifndef _CPCIHP_ZT5550_H
#define _CPCIHP_ZT5550_H
/* Direct registers */
#define CSR_HCINDEX 0x00
#define CSR_HCDATA 0x04
#define CSR_INTSTAT 0x08
#define CSR_INTMASK 0x09
#define CSR_CNT0CMD 0x0C
#define CSR_CNT1CMD 0x0E
#define CSR_CNT0 0x10
#define CSR_CNT1 0x14
/* Masks for interrupt bits in CSR_INTMASK direct register */
#define CNT0_INT_MASK 0x01
#define CNT1_INT_MASK 0x02
#define ENUM_INT_MASK 0x04
#define ALL_DIRECT_INTS_MASK 0x07
/* Indexed registers (through CSR_INDEX, CSR_DATA) */
#define HC_INT_MASK_REG 0x04
#define HC_STATUS_REG 0x08
#define HC_CMD_REG 0x0C
#define ARB_CONFIG_GNT_REG 0x10
#define ARB_CONFIG_CFG_REG 0x12
#define ARB_CONFIG_REG 0x10
#define ISOL_CONFIG_REG 0x18
#define FAULT_STATUS_REG 0x20
#define FAULT_CONFIG_REG 0x24
#define WD_CONFIG_REG 0x2C
#define HC_DIAG_REG 0x30
#define SERIAL_COMM_REG 0x34
#define SERIAL_OUT_REG 0x38
#define SERIAL_IN_REG 0x3C
/* Masks for interrupt bits in HC_INT_MASK_REG indexed register */
#define SERIAL_INT_MASK 0x01
#define FAULT_INT_MASK 0x02
#define HCF_INT_MASK 0x04
#define ALL_INDEXED_INTS_MASK 0x07
/* Digital I/O port storing ENUM# */
#define ENUM_PORT 0xE1
/* Mask to get to the ENUM# bit on the bus */
#define ENUM_MASK 0x40
#endif /* _CPCIHP_ZT5550_H */
......@@ -167,5 +167,9 @@ extern int pci_visit_dev (struct pci_visit *fn,
struct pci_dev_wrapped *wrapped_dev,
struct pci_bus_wrapped *wrapped_parent);
int pci_is_dev_in_use(struct pci_dev *dev);
int pci_remove_device_safe(struct pci_dev *dev);
#endif
......@@ -94,15 +94,12 @@ static int pci_visit_bus (struct pci_visit * fn, struct pci_bus_wrapped *wrapped
static int pci_visit_bridge (struct pci_visit * fn, struct pci_dev_wrapped *wrapped_dev, struct pci_bus_wrapped *wrapped_parent)
{
struct pci_bus *bus = wrapped_dev->dev->subordinate;
struct pci_bus *bus;
struct pci_bus_wrapped wrapped_bus;
int result;
memset(&wrapped_bus, 0, sizeof(struct pci_bus_wrapped));
wrapped_bus.bus = bus;
int result = 0;
dbg("scanning bridge %02x, %02x\n", wrapped_dev->dev->devfn >> 3,
wrapped_dev->dev->devfn & 0x7);
dbg("scanning bridge %02x, %02x\n", PCI_SLOT(wrapped_dev->dev->devfn),
PCI_FUNC(wrapped_dev->dev->devfn));
if (fn->visit_pci_dev) {
result = fn->visit_pci_dev(wrapped_dev, wrapped_parent);
......@@ -110,7 +107,13 @@ static int pci_visit_bridge (struct pci_visit * fn, struct pci_dev_wrapped *wrap
return result;
}
result = pci_visit_bus(fn, &wrapped_bus, wrapped_dev);
bus = wrapped_dev->dev->subordinate;
if(bus) {
memset(&wrapped_bus, 0, sizeof(struct pci_bus_wrapped));
wrapped_bus.bus = bus;
result = pci_visit_bus(fn, &wrapped_bus, wrapped_dev);
}
return result;
}
......@@ -153,6 +156,62 @@ int pci_visit_dev (struct pci_visit *fn, struct pci_dev_wrapped *wrapped_dev, st
return result;
}
/**
* pci_is_dev_in_use - query devices' usage
* @dev: PCI device to query
*
* Queries whether a given PCI device is in use by a driver or not.
* Returns 1 if the device is in use, 0 if it is not.
*/
int pci_is_dev_in_use(struct pci_dev *dev)
{
/*
* dev->driver will be set if the device is in use by a new-style
* driver -- otherwise, check the device's regions to see if any
* driver has claimed them.
*/
int i;
int inuse = 0;
if (dev->driver) {
/* Assume driver feels responsible */
return 1;
}
for (i = 0; !dev->driver && !inuse && (i < 6); i++) {
if (!pci_resource_start(dev, i))
continue;
if (pci_resource_flags(dev, i) & IORESOURCE_IO) {
inuse = check_region(pci_resource_start(dev, i),
pci_resource_len(dev, i));
} else if (pci_resource_flags(dev, i) & IORESOURCE_MEM) {
inuse = check_mem_region(pci_resource_start(dev, i),
pci_resource_len(dev, i));
}
}
return inuse;
}
/**
* pci_remove_device_safe - remove an unused hotplug device
* @dev: the device to remove
*
* Delete the device structure from the device lists and
* notify userspace (/sbin/hotplug), but only if the device
* in question is not being used by a driver.
* Returns 0 on success.
*/
int pci_remove_device_safe(struct pci_dev *dev)
{
if (pci_is_dev_in_use(dev)) {
return -EBUSY;
}
pci_remove_device(dev);
return 0;
}
EXPORT_SYMBOL(pci_visit_dev);
EXPORT_SYMBOL(pci_is_dev_in_use);
EXPORT_SYMBOL(pci_remove_device_safe);
......@@ -3,7 +3,7 @@
#
export-objs := access.o hotplug.o pci-driver.o pci.o pool.o \
probe.o proc.o search.o compat.o
probe.o proc.o search.o compat.o setup-bus.o
obj-y += access.o probe.o pci.o pool.o quirks.o \
compat.o names.o pci-driver.o search.o hotplug.o
......@@ -25,6 +25,11 @@ obj-$(CONFIG_PPC32) += setup-irq.o
obj-$(CONFIG_DDB5476) += setup-bus.o
obj-$(CONFIG_SGI_IP27) += setup-irq.o
# CompactPCI hotplug requires the pbus_* functions
ifdef CONFIG_HOTPLUG_PCI_CPCI
obj-y += setup-bus.o
endif
ifndef CONFIG_X86
obj-y += syscall.o
endif
......
......@@ -71,8 +71,7 @@ int pci_hotplug (struct device *dev, char **envp, int num_envp,
* @bus: where to insert it
*
* Link the device to both the global PCI device chain and the
* per-bus list of devices, add the /proc entry, and notify
* userspace (/sbin/hotplug).
* per-bus list of devices, add the /proc entry.
*/
void
pci_insert_device(struct pci_dev *dev, struct pci_bus *bus)
......
......@@ -24,6 +24,49 @@
#define DBG(x...)
#endif
/**
* pci_bus_max_busnr - returns maximum PCI bus number of given bus' children
* @bus: pointer to PCI bus structure to search
*
* Given a PCI bus, returns the highest PCI bus number present in the set
* including the given PCI bus and its list of child PCI buses.
*/
unsigned char __devinit
pci_bus_max_busnr(struct pci_bus* bus)
{
struct list_head *tmp;
unsigned char max, n;
max = bus->number;
list_for_each(tmp, &bus->children) {
n = pci_bus_max_busnr(pci_bus_b(tmp));
if(n > max)
max = n;
}
return max;
}
/**
* pci_max_busnr - returns maximum PCI bus number
*
* Returns the highest PCI bus number present in the system global list of
* PCI buses.
*/
unsigned char __devinit
pci_max_busnr(void)
{
struct pci_bus* bus;
unsigned char max, n;
max = 0;
pci_for_each_bus(bus) {
n = pci_bus_max_busnr(bus);
if(n > max)
max = n;
}
return max;
}
/**
* pci_find_capability - query for devices' capabilities
* @dev: PCI device to query
......@@ -79,6 +122,49 @@ pci_find_capability(struct pci_dev *dev, int cap)
return 0;
}
/**
* pci_bus_find_capability - query for devices' capabilities
* @dev: PCI device to query
* @cap: capability code
*
* Like pci_find_capability() but works for pci devices that do not have a
* pci_dev structure set up yet.
* Returns the address of the requested capability structure within the
* device's PCI configuration space or 0 in case the device does not
* support it.
*/
int pci_bus_find_capability(struct pci_bus *bus, unsigned int devfn, int cap)
{
u16 status;
u8 pos, id;
int ttl = 48;
struct pci_dev *dev = bus->self;
pci_bus_read_config_word(bus, devfn, PCI_STATUS, &status);
if (!(status & PCI_STATUS_CAP_LIST))
return 0;
switch (dev->hdr_type) {
case PCI_HEADER_TYPE_NORMAL:
case PCI_HEADER_TYPE_BRIDGE:
pci_bus_read_config_byte(bus, devfn, PCI_CAPABILITY_LIST, &pos);
break;
case PCI_HEADER_TYPE_CARDBUS:
pci_bus_read_config_byte(bus, devfn, PCI_CB_CAPABILITY_LIST, &pos);
break;
default:
return 0;
}
while (ttl-- && pos >= 0x40) {
pos &= ~3;
pci_bus_read_config_byte(bus, devfn, pos + PCI_CAP_LIST_ID, &id);
if (id == 0xff)
break;
if (id == cap)
return pos;
pci_bus_read_config_byte(bus, devfn, pos + PCI_CAP_LIST_NEXT, &pos);
}
return 0;
}
/**
* pci_find_parent_resource - return resource region of parent bus of given region
......@@ -649,7 +735,10 @@ EXPORT_SYMBOL(isa_bridge);
EXPORT_SYMBOL(pci_enable_device);
EXPORT_SYMBOL(pci_disable_device);
EXPORT_SYMBOL(pci_max_busnr);
EXPORT_SYMBOL(pci_bus_max_busnr);
EXPORT_SYMBOL(pci_find_capability);
EXPORT_SYMBOL(pci_bus_find_capability);
EXPORT_SYMBOL(pci_release_regions);
EXPORT_SYMBOL(pci_request_regions);
EXPORT_SYMBOL(pci_release_region);
......
......@@ -254,7 +254,7 @@ struct pci_bus * __devinit pci_add_new_bus(struct pci_bus *parent, struct pci_de
* them, we proceed to assigning numbers to the remaining buses in
* order to avoid overlaps between old and new bus numbers.
*/
static int __devinit pci_scan_bridge(struct pci_bus *bus, struct pci_dev * dev, int max, int pass)
int __devinit pci_scan_bridge(struct pci_bus *bus, struct pci_dev * dev, int max, int pass)
{
unsigned int buses;
unsigned short cr;
......@@ -480,8 +480,7 @@ struct pci_dev * __devinit pci_scan_slot(struct pci_dev *temp)
/*
* Link the device to both the global PCI device chain and
* the per-bus list of devices and call /sbin/hotplug if we
* should.
* the per-bus list of devices and add the /proc entry.
*/
pci_insert_device (dev, bus);
......@@ -596,4 +595,5 @@ EXPORT_SYMBOL(pci_add_new_bus);
EXPORT_SYMBOL(pci_do_scan_bus);
EXPORT_SYMBOL(pci_scan_slot);
EXPORT_SYMBOL(pci_scan_bus);
EXPORT_SYMBOL(pci_scan_bridge);
#endif
......@@ -23,7 +23,7 @@
/* Deal with broken BIOS'es that neglect to enable passive release,
which can cause problems in combination with the 82441FX/PPro MTRRs */
static void __init quirk_passive_release(struct pci_dev *dev)
static void __devinit quirk_passive_release(struct pci_dev *dev)
{
struct pci_dev *d = NULL;
unsigned char dlc;
......@@ -50,7 +50,7 @@ static void __init quirk_passive_release(struct pci_dev *dev)
int isa_dma_bridge_buggy; /* Exported */
static void __init quirk_isa_dma_hangs(struct pci_dev *dev)
static void __devinit quirk_isa_dma_hangs(struct pci_dev *dev)
{
if (!isa_dma_bridge_buggy) {
isa_dma_bridge_buggy=1;
......@@ -64,7 +64,7 @@ int pci_pci_problems;
* Chipsets where PCI->PCI transfers vanish or hang
*/
static void __init quirk_nopcipci(struct pci_dev *dev)
static void __devinit quirk_nopcipci(struct pci_dev *dev)
{
if((pci_pci_problems&PCIPCI_FAIL)==0)
{
......@@ -77,7 +77,7 @@ static void __init quirk_nopcipci(struct pci_dev *dev)
* Triton requires workarounds to be used by the drivers
*/
static void __init quirk_triton(struct pci_dev *dev)
static void __devinit quirk_triton(struct pci_dev *dev)
{
if((pci_pci_problems&PCIPCI_TRITON)==0)
{
......@@ -96,7 +96,7 @@ static void __init quirk_triton(struct pci_dev *dev)
* Updated based on further information from the site and also on
* information provided by VIA
*/
static void __init quirk_vialatency(struct pci_dev *dev)
static void __devinit quirk_vialatency(struct pci_dev *dev)
{
struct pci_dev *p;
u8 rev;
......@@ -150,7 +150,7 @@ static void __init quirk_vialatency(struct pci_dev *dev)
* VIA Apollo VP3 needs ETBF on BT848/878
*/
static void __init quirk_viaetbf(struct pci_dev *dev)
static void __devinit quirk_viaetbf(struct pci_dev *dev)
{
if((pci_pci_problems&PCIPCI_VIAETBF)==0)
{
......@@ -158,7 +158,7 @@ static void __init quirk_viaetbf(struct pci_dev *dev)
pci_pci_problems|=PCIPCI_VIAETBF;
}
}
static void __init quirk_vsfx(struct pci_dev *dev)
static void __devinit quirk_vsfx(struct pci_dev *dev)
{
if((pci_pci_problems&PCIPCI_VSFX)==0)
{
......@@ -173,7 +173,7 @@ static void __init quirk_vsfx(struct pci_dev *dev)
* at least
*/
static void __init quirk_natoma(struct pci_dev *dev)
static void __devinit quirk_natoma(struct pci_dev *dev)
{
if((pci_pci_problems&PCIPCI_NATOMA)==0)
{
......@@ -187,7 +187,7 @@ static void __init quirk_natoma(struct pci_dev *dev)
* If it's needed, re-allocate the region.
*/
static void __init quirk_s3_64M(struct pci_dev *dev)
static void __devinit quirk_s3_64M(struct pci_dev *dev)
{
struct resource *r = &dev->resource[0];
......@@ -197,7 +197,7 @@ static void __init quirk_s3_64M(struct pci_dev *dev)
}
}
static void __init quirk_io_region(struct pci_dev *dev, unsigned region, unsigned size, int nr)
static void __devinit quirk_io_region(struct pci_dev *dev, unsigned region, unsigned size, int nr)
{
region &= ~(size-1);
if (region) {
......@@ -222,7 +222,7 @@ static void __init quirk_io_region(struct pci_dev *dev, unsigned region, unsigne
* 0xE0 (64 bytes of ACPI registers)
* 0xE2 (32 bytes of SMB registers)
*/
static void __init quirk_ali7101_acpi(struct pci_dev *dev)
static void __devinit quirk_ali7101_acpi(struct pci_dev *dev)
{
u16 region;
......@@ -237,7 +237,7 @@ static void __init quirk_ali7101_acpi(struct pci_dev *dev)
* 0x40 (64 bytes of ACPI registers)
* 0x90 (32 bytes of SMB registers)
*/
static void __init quirk_piix4_acpi(struct pci_dev *dev)
static void __devinit quirk_piix4_acpi(struct pci_dev *dev)
{
u32 region;
......@@ -251,7 +251,7 @@ static void __init quirk_piix4_acpi(struct pci_dev *dev)
* VIA ACPI: One IO region pointed to by longword at
* 0x48 or 0x20 (256 bytes of ACPI registers)
*/
static void __init quirk_vt82c586_acpi(struct pci_dev *dev)
static void __devinit quirk_vt82c586_acpi(struct pci_dev *dev)
{
u8 rev;
u32 region;
......@@ -270,7 +270,7 @@ static void __init quirk_vt82c586_acpi(struct pci_dev *dev)
* 0x70 (128 bytes of hardware monitoring register)
* 0x90 (16 bytes of SMB registers)
*/
static void __init quirk_vt82c686_acpi(struct pci_dev *dev)
static void __devinit quirk_vt82c686_acpi(struct pci_dev *dev)
{
u16 hm;
u32 smb;
......@@ -297,7 +297,7 @@ extern int nr_ioapics;
* TODO: When we have device-specific interrupt routers,
* this code will go away from quirks.
*/
static void __init quirk_via_ioapic(struct pci_dev *dev)
static void __devinit quirk_via_ioapic(struct pci_dev *dev)
{
u8 tmp;
......@@ -338,7 +338,7 @@ static void __init quirk_via_ioapic(struct pci_dev *dev)
* value of the ACPI SCI interrupt is only done for convenience.
* -jgarzik
*/
static void __init quirk_via_acpi(struct pci_dev *d)
static void __devinit quirk_via_acpi(struct pci_dev *d)
{
/*
* VIA ACPI device: SCI IRQ line in PCI config byte 0x42
......@@ -350,7 +350,7 @@ static void __init quirk_via_acpi(struct pci_dev *d)
d->irq = irq;
}
static void __init quirk_via_irqpic(struct pci_dev *dev)
static void __devinit quirk_via_irqpic(struct pci_dev *dev)
{
u8 irq, new_irq = dev->irq & 0xf;
......@@ -377,7 +377,7 @@ static void __init quirk_via_irqpic(struct pci_dev *dev)
*
* We mask out all r/wc bits, too.
*/
static void __init quirk_piix3_usb(struct pci_dev *dev)
static void __devinit quirk_piix3_usb(struct pci_dev *dev)
{
u16 legsup;
......@@ -392,7 +392,7 @@ static void __init quirk_piix3_usb(struct pci_dev *dev)
* We need to switch it off to be able to recognize the real
* type of the chip.
*/
static void __init quirk_vt82c598_id(struct pci_dev *dev)
static void __devinit quirk_vt82c598_id(struct pci_dev *dev)
{
pci_write_config_byte(dev, 0xfc, 0);
pci_read_config_word(dev, PCI_DEVICE_ID, &dev->device);
......@@ -404,7 +404,7 @@ static void __init quirk_vt82c598_id(struct pci_dev *dev)
* do this even if the Linux CardBus driver is not loaded, because
* the Linux i82365 driver does not (and should not) handle CardBus.
*/
static void __init quirk_cardbus_legacy(struct pci_dev *dev)
static void __devinit quirk_cardbus_legacy(struct pci_dev *dev)
{
if ((PCI_CLASS_BRIDGE_CARDBUS << 8) ^ dev->class)
return;
......@@ -421,7 +421,7 @@ static void __init quirk_cardbus_legacy(struct pci_dev *dev)
* of course. However the advice is demonstrably good even if so..
*/
static void __init quirk_amd_ioapic(struct pci_dev *dev)
static void __devinit quirk_amd_ioapic(struct pci_dev *dev)
{
u8 rev;
......@@ -441,7 +441,7 @@ static void __init quirk_amd_ioapic(struct pci_dev *dev)
* who turn it off!
*/
static void __init quirk_amd_ordering(struct pci_dev *dev)
static void __devinit quirk_amd_ordering(struct pci_dev *dev)
{
u32 pcic;
pci_read_config_dword(dev, 0x4C, &pcic);
......@@ -464,14 +464,14 @@ static void __init quirk_amd_ordering(struct pci_dev *dev)
* nothing gets put too close to it.
*/
static void __init quirk_dunord ( struct pci_dev * dev )
static void __devinit quirk_dunord ( struct pci_dev * dev )
{
struct resource * r = & dev -> resource [ 1 ];
r -> start = 0;
r -> end = 0xffffff;
}
static void __init quirk_transparent_bridge(struct pci_dev *dev)
static void __devinit quirk_transparent_bridge(struct pci_dev *dev)
{
dev->transparent = 1;
}
......@@ -480,7 +480,7 @@ static void __init quirk_transparent_bridge(struct pci_dev *dev)
* The main table of quirks.
*/
static struct pci_fixup pci_fixups[] __initdata = {
static struct pci_fixup pci_fixups[] __devinitdata = {
{ PCI_FIXUP_HEADER, PCI_VENDOR_ID_DUNORD, PCI_DEVICE_ID_DUNORD_I3000, quirk_dunord },
{ PCI_FIXUP_FINAL, PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82441, quirk_passive_release },
{ PCI_FIXUP_FINAL, PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82441, quirk_passive_release },
......
#include <linux/pci.h>
#include <linux/module.h>
static struct pci_bus *
pci_do_find_bus(struct pci_bus* bus, unsigned char busnr)
{
struct pci_bus* child;
struct list_head *tmp;
if(bus->number == busnr)
return bus;
list_for_each(tmp, &bus->children) {
child = pci_do_find_bus(pci_bus_b(tmp), busnr);
if(child)
return child;
}
return NULL;
}
/**
* pci_find_bus - locate PCI bus from a given bus number
* @busnr: number of desired PCI bus
*
* Given a PCI bus number, the desired PCI bus is located in system
* global list of PCI buses. If the bus is found, a pointer to its
* data structure is returned. If no bus is found, %NULL is returned.
*/
struct pci_bus *
pci_find_bus(unsigned char busnr)
{
struct pci_bus* bus;
struct pci_bus* tmp_bus;
pci_for_each_bus(bus) {
tmp_bus = pci_do_find_bus(bus, busnr);
if(tmp_bus)
return tmp_bus;
}
return NULL;
}
/**
* pci_find_slot - locate PCI device from a given PCI slot
* @bus: number of PCI bus on which desired PCI device resides
......@@ -104,6 +143,7 @@ pci_find_class(unsigned int class, const struct pci_dev *from)
return NULL;
}
EXPORT_SYMBOL(pci_find_bus);
EXPORT_SYMBOL(pci_find_class);
EXPORT_SYMBOL(pci_find_device);
EXPORT_SYMBOL(pci_find_slot);
......
......@@ -19,6 +19,7 @@
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/errno.h>
#include <linux/ioport.h>
......@@ -35,7 +36,7 @@
#define ROUND_UP(x, a) (((x) + (a) - 1) & ~((a) - 1))
static int __init
static int __devinit
pbus_assign_resources_sorted(struct pci_bus *bus)
{
struct list_head *ln;
......@@ -85,7 +86,7 @@ pbus_assign_resources_sorted(struct pci_bus *bus)
requires that if there is no I/O ports or memory behind the
bridge, corresponding range must be turned off by writing base
value greater than limit to the bridge's base/limit registers. */
static void __init
static void __devinit
pci_setup_bridge(struct pci_bus *bus)
{
struct pbus_set_ranges_data ranges;
......@@ -168,7 +169,7 @@ pci_setup_bridge(struct pci_bus *bus)
/* Check whether the bridge supports optional I/O and
prefetchable memory ranges. If not, the respective
base/limit registers must be read-only and read as 0. */
static void __init
static void __devinit
pci_bridge_check_ranges(struct pci_bus *bus)
{
u16 io;
......@@ -210,7 +211,7 @@ pci_bridge_check_ranges(struct pci_bus *bus)
since these windows have 4K granularity and the IO ranges
of non-bridge PCI devices are limited to 256 bytes.
We must be careful with the ISA aliasing though. */
static void __init
static void __devinit
pbus_size_io(struct pci_bus *bus)
{
struct list_head *ln;
......@@ -259,7 +260,7 @@ pbus_size_io(struct pci_bus *bus)
/* Calculate the size of the bus and minimal alignment which
guarantees that all child resources fit in this size. */
static void __init
static void __devinit
pbus_size_mem(struct pci_bus *bus, unsigned long mask, unsigned long type)
{
struct list_head *ln;
......@@ -331,7 +332,7 @@ pbus_size_mem(struct pci_bus *bus, unsigned long mask, unsigned long type)
b_res->end = size + min_align - 1;
}
void __init
void __devinit
pbus_size_bridges(struct pci_bus *bus)
{
struct list_head *ln;
......@@ -357,8 +358,9 @@ pbus_size_bridges(struct pci_bus *bus)
}
pbus_size_mem(bus, mask, type);
}
EXPORT_SYMBOL(pbus_size_bridges);
void __init
void __devinit
pbus_assign_resources(struct pci_bus *bus)
{
struct list_head *ln;
......@@ -379,6 +381,7 @@ pbus_assign_resources(struct pci_bus *bus)
pci_setup_bridge(b);
}
}
EXPORT_SYMBOL(pbus_assign_resources);
void __init
pci_assign_unassigned_resources(void)
......
......@@ -557,8 +557,12 @@ struct pci_dev *pci_find_subsys (unsigned int vendor, unsigned int device,
unsigned int ss_vendor, unsigned int ss_device,
const struct pci_dev *from);
struct pci_dev *pci_find_class (unsigned int class, const struct pci_dev *from);
struct pci_bus *pci_find_bus(unsigned char busnr);
struct pci_dev *pci_find_slot (unsigned int bus, unsigned int devfn);
unsigned char pci_bus_max_busnr(struct pci_bus* bus);
unsigned char pci_max_busnr(void);
int pci_find_capability (struct pci_dev *dev, int cap);
int pci_bus_find_capability (struct pci_bus *bus, unsigned int devfn, int cap);
int pci_bus_read_config_byte (struct pci_bus *bus, unsigned int devfn, int where, u8 *val);
int pci_bus_read_config_word (struct pci_bus *bus, unsigned int devfn, int where, u16 *val);
......@@ -613,6 +617,8 @@ int pci_enable_wake(struct pci_dev *dev, u32 state, int enable);
/* Helper functions for low-level code (drivers/pci/setup-[bus,res].c) */
void pbus_assign_resources(struct pci_bus *bus);
void pbus_size_bridges(struct pci_bus *bus);
int pci_claim_resource(struct pci_dev *, int);
void pci_assign_unassigned_resources(void);
void pdev_enable_device(struct pci_dev *);
......@@ -634,6 +640,7 @@ struct pci_driver *pci_dev_driver(const struct pci_dev *);
const struct pci_device_id *pci_match_device(const struct pci_device_id *ids, const struct pci_dev *dev);
unsigned int pci_do_scan_bus(struct pci_bus *bus);
struct pci_bus * pci_add_new_bus(struct pci_bus *parent, struct pci_dev *dev, int busnr);
int pci_scan_bridge(struct pci_bus *bus, struct pci_dev * dev, int max, int pass);
/* kmem_cache style wrapper around pci_alloc_consistent() */
struct pci_pool *pci_pool_create (const char *name, struct pci_dev *dev,
......
......@@ -1100,6 +1100,9 @@
#define PCI_DEVICE_ID_EICON_MAESTRAQ 0xe012
#define PCI_DEVICE_ID_EICON_MAESTRAQ_U 0xe013
#define PCI_DEVICE_ID_EICON_MAESTRAP 0xe014
#define PCI_VENDOR_ID_ZIATECH 0x1138
#define PCI_DEVICE_ID_ZIATECH_5550_HC 0x5550
#define PCI_VENDOR_ID_CYCLONE 0x113c
#define PCI_DEVICE_ID_CYCLONE_SDK 0x0001
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment