linux-hotplug.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
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");


  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).