From: Greg KH <greg@kroah.com>
To: linux-hotplug@vger.kernel.org
Subject: Re: PCI hotplug question: resources
Date: Thu, 07 Feb 2002 23:51:48 +0000 [thread overview]
Message-ID: <marc-linux-hotplug-101312609603679@msgid-missing> (raw)
In-Reply-To: <marc-linux-hotplug-101290913112826@msgid-missing>
[-- Attachment #1: Type: text/plain, Size: 423 bytes --]
On Thu, Feb 07, 2002 at 08:42:46AM -0800, Stephen Williams wrote:
>
> I spend lot of time during a typical day powering down, changing
> the board and/or soldering wires, and rebooting. I would *love*
> to be able to just change a card on a live system.
Ok, here's the code that I have. I don't know if this works. Heck,
I've never even compiled it :)
This code was written by Vladimir Kondratiev.
thanks,
greg k-h
[-- Attachment #2: pcibus.c --]
[-- Type: text/plain, Size: 8224 bytes --]
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/init.h>
#include <linux/errno.h>
/* for pci_print_IRQ_route */
#include <../arch/i386/kernel/pci-i386.h>
static int assign_irq=0;
/* borrow from pci.c, I need it with no __initdev */
struct pci_dev * pci_scan_device(struct pci_dev *temp)
{
struct pci_dev *dev;
u32 l;
if (pci_read_config_dword(temp, PCI_VENDOR_ID, &l))
return NULL;
/* some broken boards return 0 or ~0 if a slot is empty: */
if (l == 0xffffffff || l == 0x00000000 || l == 0x0000ffff || l == 0xffff0000)
return NULL;
dev = kmalloc(sizeof(*dev), GFP_KERNEL);
if (!dev)
return NULL;
memcpy(dev, temp, sizeof(*dev));
dev->vendor = l & 0xffff;
dev->device = (l >> 16) & 0xffff;
/* Assume 32-bit PCI; let 64-bit PCI cards (which are far rarer)
set this higher, assuming the system even supports it. */
dev->dma_mask = 0xffffffff;
if (pci_setup_device(dev) < 0) {
kfree(dev);
dev = NULL;
}
return dev;
}
#if 1
/* as in compaq hotplug driver, but print more info */
static int pci_print_IRQ_route (void)
{
struct irq_routing_table *routing_table;
int len;
int loop;
u8 tbus, tdevice, tslot;
routing_table = pcibios_get_irq_routing_table();
if (routing_table == NULL) {
printk(KERN_ERR "No BIOS Routing Table??? Not good\n");
return -ENOMEM;
}
len = (routing_table->size - sizeof(struct irq_routing_table)) / sizeof(struct irq_info);
// Make sure I got at least one entry
if (len == 0) {
kfree(routing_table);
return -1;
}
printk(KERN_INFO "IRQ router %2x:%2x.%d %04x:%04x\n",
(unsigned int)routing_table->rtr_bus,
(unsigned int)PCI_SLOT(routing_table->rtr_devfn),
(unsigned int)PCI_FUNC(routing_table->rtr_devfn),
(unsigned int)routing_table->rtr_vendor,(unsigned int)routing_table->rtr_device);
printk(KERN_INFO "Exclusive IRQs %04x\n",(unsigned int)routing_table->exclusive_irqs);
printk(KERN_INFO "bus dev func slot\n");
for (loop = 0; loop < len; ++loop) {
tbus = routing_table->slots[loop].bus;
tdevice = routing_table->slots[loop].devfn;
tslot = routing_table->slots[loop].slot;
printk(KERN_INFO "%d %d %d %d\n",
(unsigned int)tbus,
(unsigned int)PCI_SLOT(tdevice),
(unsigned int)PCI_FUNC(tdevice),
(unsigned int)tslot);
{
int i;
for (i=0;i<4;i++) {
printk(KERN_INFO " int%c %02x %04x\n", 'A'+i,
(unsigned int)routing_table->slots[loop].irq[i].link,
(unsigned int)routing_table->slots[loop].irq[i].bitmap);
}
}
}
kfree(routing_table);
return 0;
}
#endif
#if 0
struct irq_info {
u8 bus, devfn; /* Bus, device and function */
struct {
u8 link; /* IRQ line ID, chipset dependent, 0=not routed */
u16 bitmap; /* Available IRQs */
} __attribute__((packed)) irq[4];
u8 slot; /* Slot number, 0=onboard */
u8 rfu;
} __attribute__((packed));
struct irq_routing_table {
u32 signature; /* PIRQ_SIGNATURE should be here */
u16 version; /* PIRQ_VERSION */
u16 size; /* Table size in bytes */
u8 rtr_bus, rtr_devfn; /* Where the interrupt router lies */
u16 exclusive_irqs; /* IRQs devoted exclusively to PCI usage */
u16 rtr_vendor, rtr_device; /* Vendor and device ID of interrupt router */
u32 miniport_data; /* Crap */
u8 rfu[11];
u8 checksum; /* Modulo 256 checksum must give zero */
struct irq_info slots[0];
} __attribute__((packed));
#endif
struct pci_dev* pci_rescan_new_dev(struct pci_dev *dev)
{
int i;
for (i=0;i<DEVICE_COUNT_RESOURCE;i++) {
pci_assign_resource(dev,i);
}
/* Does this function have an interrupt at all? */
{
__u8 irq_pin;
pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &irq_pin);
if (irq_pin) {
if ( !dev->irq ) dev->irq = assign_irq;
pci_write_config_byte(dev, PCI_INTERRUPT_LINE, dev->irq);
}
}
/*pci_name_device(dev);*/
printk(KERN_INFO "Slot %s New <%s>\n", dev->slot_name, dev->name);
/* Fix up broken headers */
#if 0 /* not exported by kernel, init time only */
pci_fixup_device(PCI_FIXUP_HEADER, dev);
#endif
/* FIXME insert new device */
if (pci_enable_device(dev)) {
printk(KERN_ERR "pci_enable_device failed\n");
kfree(dev);
return NULL;
}
pci_insert_device(dev,dev->bus);
return dev;
}
/**
* Rescan slot.
* First, determine whether card in the slot has changed. It is
* done by compare of old and actual devices for function 0.
* If change detected, old device(s) removed, other functions
* scanned if it is multi-function dev, new devices inserted.
*
* @param temp Device template. Should be set: bus and devfn.
* @return Device for function 0
*/
struct pci_dev* pci_rescan_slot(struct pci_dev *temp)
{
struct pci_bus *bus = temp->bus;
struct pci_dev* old_dev=pci_find_slot(bus->number,temp->devfn);
struct pci_dev *dev=NULL;
struct pci_dev *first_dev = NULL;
int func = 0;
int new_multi = 0; /* new multifunction device */
u8 hdr_type;
/* function 0 */
if (!pci_read_config_byte(temp, PCI_HEADER_TYPE, &hdr_type)) {
temp->hdr_type = hdr_type & 0x7f;
dev = pci_scan_device(temp);
if (dev) {
/* compare with old device to detect card change */
if (old_dev) {
if (old_dev->vendor==dev->vendor && old_dev->device==dev->device) {
kfree(dev);
return old_dev;
} else {
printk(KERN_INFO "Slot %02x:%02x Device changed!\n",
(unsigned int)bus->number,(unsigned int)PCI_SLOT(temp->devfn));
printk(KERN_INFO " Old one <%s>\n",old_dev->name);
printk(KERN_INFO " New one <%s>\n",dev->name);
for (func=0;func<8;func++) {
old_dev=pci_find_slot(bus->number,temp->devfn+func);
if (old_dev) {
printk(KERN_INFO "Slot %s Removed <%s>\n", old_dev->slot_name,old_dev->name);
pci_remove_device(old_dev);
}
}
}
}
/* new device found */
printk(KERN_INFO "Slot %02x:%02x New <%s>\n",
(unsigned int)bus->number,(unsigned int)PCI_SLOT(temp->devfn),
dev->name);
dev=pci_rescan_new_dev(dev);
first_dev=dev;
new_multi=hdr_type & 0x80;
}
}
if ( !dev && old_dev ) { /* device removed */
for (func=0;func<8;func++) {
old_dev=pci_find_slot(bus->number,temp->devfn+func);
if (old_dev) {
printk(KERN_INFO "Slot %s Removed <%s>\n", old_dev->slot_name,old_dev->name);
pci_remove_device(old_dev);
}
}
}
if (new_multi) { /* continue scanning for other functions */
for (func = 1, temp->devfn++; func < 8; func++, temp->devfn++) {
if (pci_read_config_byte(temp, PCI_HEADER_TYPE, &hdr_type))
continue;
temp->hdr_type = hdr_type & 0x7f;
dev = pci_scan_device(temp);
if (dev) {
dev=pci_rescan_new_dev(dev);
}
}
}
return first_dev;
}
/**
* Rescan PCI bus.
* Assumed, some slots may have changed its content.
* Find old information about each slot and the new one.
* If they match, do nothing. Otherwise,
* remove/insert proper devices.
*
* @param bus
*/
static void pci_rescan_bus(const struct pci_bus *bus)
{
unsigned int devfn;
struct pci_dev dev0;
memset(&dev0, 0, sizeof(dev0));
dev0.bus = (struct pci_bus*)bus;
dev0.sysdata = bus->sysdata;
for (devfn = 0; devfn < 0x100; devfn += 8) {
dev0.devfn = devfn;
pci_rescan_slot(&dev0);
}
}
static void pci_rescan_buses(const struct list_head *list)
{
const struct list_head *l;
list_for_each(l,list) {
const struct pci_bus *b = pci_bus_b(l);
pci_rescan_bus(b);
pci_rescan_buses(&b->children);
}
}
static int pci_rescan_init(void)
{
pci_rescan_buses(&pci_root_buses);
pci_print_IRQ_route();
return -ENODEV;
}
static void pci_rescan_exit(void)
{}
module_init(pci_rescan_init);
module_exit(pci_rescan_exit);
MODULE_PARM(assign_irq,"i");
MODULE_PARM_DESC(assign_irq,"IRQ to assign to new cards");
MODULE_DESCRIPTION("Force PCI bus rescan");
MODULE_AUTHOR("Vladimir Kondratiev, vladimir.kondratiev@intel.com");
next prev parent reply other threads:[~2002-02-07 23:51 UTC|newest]
Thread overview: 11+ messages / expand[flat|nested] mbox.gz Atom feed top
2002-02-05 11:37 PCI hotplug question: resources Dirk Stieler
2002-02-05 13:55 ` Matti Aarnio
2002-02-06 1:17 ` Stephen Williams
2002-02-06 10:20 ` Matti Aarnio
2002-02-06 17:55 ` Chris Brand
2002-02-07 8:43 ` Greg KH
2002-02-07 16:42 ` Stephen Williams
2002-02-07 23:51 ` Greg KH [this message]
2002-02-08 1:06 ` Donald Becker
2002-02-08 1:34 ` Martin Diehl
2002-02-08 15:44 ` John Carlson
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=marc-linux-hotplug-101312609603679@msgid-missing \
--to=greg@kroah.com \
--cc=linux-hotplug@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).