All of lore.kernel.org
 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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.