Re: cPCI Hotplug support

From: william wallace <avalonwallace_at_gmail.com>
Date: Mon, 8 May 2006 10:11:49 +0800
hello ,everyone .
        i have write a demo module to demostrate the hotplug of a pci
device under freeBSD 5.3 . when kldload the module ,the fakedevice will be
"plug "into the pci architechure,when kldunload ,the device will be removed.
pciconf -l ,and devinfo -v will be the tool to show this change : a new
device called wallace is added ,this device comes from the info in LINE97 of
the fakeBSC.c:
 *dinfo=* ((struct pci_devinfo *)  device_get_ivars(devlist[6])  );
maybe u need to change the '6' according to ur need .

there r 4 file in this package :pci_hotplug_core.c fakeBSD.c pci_hotplug.h
and the Makefile .

way to RUN:
1 unzip the package
2 make
3 kldload ./fakeBSD.ko
4 pciconf -l ,and devinfo -v to see the change
5 kldunload fakeBSD.ko
welcome for ur feedback,next i will do my best to write the  driver for real
pci device hotplug, as what cardbus has done

////////////////pci_hotplug_core.c//////////////////////////////////

/////////////from PCIexample////////////////
#include <sys/param.h>  /* defines used in kernel.h */
#include <sys/module.h>
#include <sys/systm.h>
#include <sys/errno.h>
#include <sys/kernel.h> /* types used in module initialization */
#include <sys/conf.h>   /* cdevsw struct */
#include <sys/uio.h>    /* uio struct */
#include <sys/malloc.h>
#include <sys/bus.h>  /* structs, prototypes for pci bus stuff */

#include <machine/bus.h>
#include <sys/rman.h>
#include <machine/resource.h>

#include <dev/pci/pcivar.h> /* For get_pci macros! */
#include <dev/pci/pcireg.h>
 ////////////////////////////////////
#include<dev/drm/drm_linux_list.h>
#include "pci_hotplug.h"

//WB//
#define MY_NAME "pci_hotplug"
//simplified//WB//
#define dbg(fmt, arg...) do { if (debug) printf( fmt , ## arg); } while (0)
#define err(format, arg...) printf( format, MY_NAME , ## arg)
#define info(format, arg...) printf(format, MY_NAME , ## arg)
#define warn(format, arg...) printf(format ,  MY_NAME, ## arg)


/* local variables */
static int debug;

//////////////////////////////////////////////////////////////////

static LIST_HEAD(pci_hotplug_slot_list);

/* these strings match up with the values in pci_bus_speed */
static char *pci_bus_speed_strings[] = {
 "33 MHz PCI",  /* 0x00 */
 "66 MHz PCI",  /* 0x01 */
 "66 MHz PCIX",   /* 0x02 */
 "100 MHz PCIX",  /* 0x03 */
 "133 MHz PCIX",  /* 0x04 */
 NULL,   /* 0x05 */
 NULL,   /* 0x06 */
 NULL,   /* 0x07 */
 NULL,   /* 0x08 */
 "66 MHz PCIX 266", /* 0x09 */
 "100 MHz PCIX 266", /* 0x0a */
 "133 MHz PCIX 266", /* 0x0b */
 NULL,   /* 0x0c */
 NULL,   /* 0x0d */
 NULL,   /* 0x0e */
 NULL,   /* 0x0f */
 NULL,   /* 0x10 */
 "66 MHz PCIX 533", /* 0x11 */
 "100 MHz PCIX 533", /* 0x12 */
 "133 MHz PCIX 533", /* 0x13 */
 "25 GBps PCI-E", /* 0x14 */
};



 ///////////////////fakeBSD.c
/////////////////////////////////////////////////

////////change of the header/////////////
/////////////from PCIexample////////////////
#include <sys/param.h>  /* defines used in kernel.h */
#include <sys/module.h>
#include <sys/systm.h>
#include <sys/errno.h>
#include <sys/kernel.h> /* types used in module initialization */
#include <sys/conf.h>   /* cdevsw struct */
#include <sys/uio.h>    /* uio struct */
#include <sys/malloc.h>
#include <sys/bus.h>  /* structs, prototypes for pci bus stuff */
//for TAILQ_FOREACH
//#include <sys/queue.h>
//
#include <sys/bus.h>  //1129
#include <machine/bus.h>
#include <sys/rman.h>
#include <machine/resource.h>

#include <sys/pciio.h>//1129 sizeof
#include <dev/pci/pcivar.h> /* For get_pci macros! */
#include <dev/pci/pcireg.h>
#include <dev/pci/pci_private.h>//1129
////////////////////////////////////
#include<dev/drm/drm_linux_list.h>  //for list_head
//#include "pci_hotplug.h"  put the unrealated functions out

//#include "../pci.h"

//this is created on compiling.so leave it to makefile
//#include "pcib_if.h" //#include "pci_if.h"

/*
//COMMENT
//devinfo struct for devinfo
//addtodevice_list for pciconf
COPY the NIC device content to the wallace0 fake device
*/
#define MY_NAME "fakephp"

#define dbg(fmt, arg...) do { if (debug) printf( fmt , ## arg); } while (0)
#define err(format, arg...) printf( format, MY_NAME , ## arg)
#define info(format, arg...) printf(format, MY_NAME , ## arg)



#define DRIVER_AUTHOR "Wallace <avalonwallace_at_gmail.com>"
#define DRIVER_DESC "Fake PCI Hot Plug Controller Driver"


 /*
 * This function is called by the kld[un]load(2) system calls to
 * determine what actions to take when a module is loaded or unloaded.
 */
 /* vars */

 static struct pci_devinfo *dinfo;
 static device_t bus; //refer to pci bus


 size_t dinfo_size;
static int
fake_loader(struct module *m, int what, void *arg)
{
 int erro=0;
      device_t *devlist;
 int count=0; int numdevs;
 devclass_t class1;
      char * Dtarget="pci",Dname="wallace";
      struct devlist *devlist_head;
 devlist_head = &pci_devq;
  switch (what) {
  case MOD_LOAD:                /* kldload */
      printf("Module loaded.\n,with bootverbose=%i",bootverbose);
      //find pci devclass and device
      if ((class1 = devclass_find(Dtarget)) == NULL) {
 printf("unable to get the class");
 return ENXIO;
 }
 printf("\n//////////////my name is
%s////////////\n",devclass_get_name(class1));
 // show the nameof the device,or store them into another TAILQ
 printf("maxunit under class pci
is%i\n",devclass_get_maxunit(class1)); //WB does unit == count
 if((bus = devclass_get_device(class1,count))!=NULL)//WB why not use the
loop over count?
 {
 printf("my device name is %s,my unit is %i, DESC: %s,with number:%i\n",
 device_get_name(bus),device_get_unit(bus),device_get_desc(bus),pcib_get_bus(bus));
 }
  //else? return (NULL)
      dinfo_size=sizeof(struct pci_devinfo);
      dinfo=NULL;   //initialized
      dinfo= malloc(dinfo_size, M_DEVBUF, M_WAITOK | M_ZERO);
      if (dinfo == NULL)
 return (NULL);
 if (device_get_children(bus, &devlist, &numdevs)==0)
 //get ivar from de0,thus 6 of devlist ,hardcoded ,this need specific
platform characteristic , waiting for modification
    *dinfo=* ((struct pci_devinfo *)  device_get_ivars(devlist[6])  );

      if ((dinfo->cfg.dev = device_add_child(bus, "wallace", -1)) == NULL)
{//change the name
 device_printf(device_get_parent(bus), "couldn't attach pci bus\n");

   }
   device_sysctl_init(dinfo->cfg.dev);
   strncpy ((dinfo->conf.pd_name),device_get_name(dinfo->cfg.dev
),8);//sizeof(device_get_name(dinfo->cfg.dev)));
   STAILQ_INSERT_TAIL(devlist_head, dinfo, pci_links);
   pci_numdevs++;
 pci_generation++;
   device_set_ivars(dinfo->cfg.dev, dinfo);


      //show result
      if (device_get_children(bus, &devlist, &numdevs)==0)
 while (numdevs--){
 printf("%i",numdevs);
 device_print_prettyname(devlist[numdevs]);
 if (device_get_devclass(devlist[numdevs])!=NULL )

printf("devclass=%s\n",devclass_get_name(device_get_devclass(devlist[numdevs])
));

 }

      break;
  case MOD_UNLOAD:
      printf("Module unloaded.\n");

  //still dinfo point to the fake device i point to . it is static !!!:)
      if (dinfo->cfg.dev != NULL) {
       printf("dinfo->cfg.dev exist,deleting it.\n");
 device_delete_child(device_get_parent(dinfo->cfg.dev), dinfo->cfg.dev);
 printf("dinfo->cfg.dev exist,deleted .\n");
 }else printf("dinfo->cfg.dev=NULL\n");

 if (device_get_children(bus, &devlist, &numdevs)==0)
 //demostrating the result
 while (numdevs--){
 printf("%i",numdevs);
 device_print_prettyname(devlist[numdevs]);
 if (device_get_devclass(devlist[numdevs])!=NULL )

printf("devclass=%s\n",devclass_get_name(device_get_devclass(devlist[numdevs])
));

 }

 printf("freeing(dinfo,M_DEVBUF)\n");
 //1
 device_sysctl_fini(dinfo->cfg.dev);//WB finish sysctl structure
 devlist_head = &pci_devq;
 STAILQ_REMOVE(devlist_head, dinfo, pci_devinfo, pci_links);
 free(dinfo, M_DEVBUF);
 /* increment the generation count */
 //WB inrease or decreas?
 pci_generation++;
 /* we're losing one device */
 pci_numdevs--;

 dinfo=NULL;
 //2
 printf("freed  dinfo,\n");  //WB ,n->,/n
 //erro=0;
      break;
  default:
      printf("Module default.\n");
      erro = EINVAL;
      break;
  }
  return(erro);
}



//DEV_MODULE(echo,echo_loader,NULL);
//#define DEV_MODULE(name, evh, arg)
static moduledata_t fake_mod = {
  "fakeBSD",
   fake_loader,
   NULL
};
DECLARE_MODULE(fake, fake_mod, SI_SUB_DRIVERS, SI_ORDER_MIDDLE);


//////////////////////pci_hotplug.h ///////////////////////

#include <sys/types.h> //WB//
#ifndef _PCI_HOTPLUG_H
#define _PCI_HOTPLUG_H


/* These values come from the PCI Hotplug Spec */
enum pci_bus_speed {
 PCI_SPEED_33MHz   = 0x00,
 PCI_SPEED_66MHz   = 0x01,
 PCI_SPEED_66MHz_PCIX  = 0x02,
 PCI_SPEED_100MHz_PCIX  = 0x03,
 PCI_SPEED_133MHz_PCIX  = 0x04,
 PCI_SPEED_66MHz_PCIX_ECC = 0x05,
 PCI_SPEED_100MHz_PCIX_ECC = 0x06,
 PCI_SPEED_133MHz_PCIX_ECC = 0x07,
 PCI_SPEED_66MHz_PCIX_266 = 0x09,
 PCI_SPEED_100MHz_PCIX_266 = 0x0a,
 PCI_SPEED_133MHz_PCIX_266 = 0x0b,
 PCI_SPEED_66MHz_PCIX_533 = 0x11,
 PCI_SPEED_100MHz_PCIX_533 = 0x12,
 PCI_SPEED_133MHz_PCIX_533 = 0x13,
 PCI_SPEED_UNKNOWN  = 0xff,
};

/* These values come from the PCI Express Spec */
enum pcie_link_width {
 PCIE_LNK_WIDTH_RESRV = 0x00,
 PCIE_LNK_X1  = 0x01,
 PCIE_LNK_X2  = 0x02,
 PCIE_LNK_X4  = 0x04,
 PCIE_LNK_X8  = 0x08,
 PCIE_LNK_X12  = 0x0C,
 PCIE_LNK_X16  = 0x10,
 PCIE_LNK_X32  = 0x20,
 PCIE_LNK_WIDTH_UNKNOWN  = 0xFF,
};

enum pcie_link_speed {
 PCIE_2PT5GB  = 0x14,
 PCIE_LNK_SPEED_UNKNOWN = 0xFF,
};

struct hotplug_slot;
/*//WB//
struct hotplug_slot_attribute {
 struct attribute attr;
 ssize_t (*show)(struct hotplug_slot *, char *);
 ssize_t (*store)(struct hotplug_slot *, const char *, size_t);
};
//WB//
#define to_hotplug_attr(n) container_of(n, struct hotplug_slot_attribute,
attr);


 * struct hotplug_slot_ops -the callbacks that the hotplug pci core can use
 * _at_owner: The module owner of this structure
 * _at_enable_slot: Called when the user wants to enable a specific pci slot
 * _at_disable_slot: Called when the user wants to disable a specific pci slot
 * _at_set_attention_status: Called to set the specific slot's attention LED to
 * the specified value
 * _at_hardware_test: Called to run a specified hardware test on the specified
 * slot.
 * _at_get_power_status: Called to get the current power status of a slot.
 *  If this field is NULL, the value passed in the struct hotplug_slot_info
 *  will be used when this value is requested by a user.
 * _at_get_attention_status: Called to get the current attention status of a
slot.
 * If this field is NULL, the value passed in the struct hotplug_slot_info
 * will be used when this value is requested by a user.
 * _at_get_latch_status: Called to get the current latch status of a slot.
 * If this field is NULL, the value passed in the struct hotplug_slot_info
 * will be used when this value is requested by a user.
 * _at_get_adapter_status: Called to get see if an adapter is present in the
slot or not.
 * If this field is NULL, the value passed in the struct hotplug_slot_info
 * will be used when this value is requested by a user.
 * _at_get_address: Called to get pci address of a slot.
 * If this field is NULL, the value passed in the struct hotplug_slot_info
 * will be used when this value is requested by a user.
 * _at_get_max_bus_speed: Called to get the max bus speed for a slot.
 * If this field is NULL, the value passed in the struct hotplug_slot_info
 * will be used when this value is requested by a user.
 * _at_get_cur_bus_speed: Called to get the current bus speed for a slot.
 * If this field is NULL, the value passed in the struct hotplug_slot_info
 * will be used when this value is requested by a user.
 *
 * The table of function pointers that is passed to the hotplug pci core by
a
 * hotplug pci driver.  These functions are called by the hotplug pci core
when
 * the user wants to do something to a specific slot (query it for
information,
 * set an LED, enable / disable power, etc.)
 */
 //the freebsd WAY of function call back
 typedef int enable_slot_t  (struct hotplug_slot *slot);
 typedef int disable_slot_t  (struct hotplug_slot *slot);
typedef int set_attention_status_t (struct hotplug_slot *slot, u_int8_t
value);
typedef int hardware_test_t  (struct hotplug_slot *slot, u_int32_t value);
typedef int get_power_status_t  (struct hotplug_slot *slot, u_int8_t
*value);
typedef int get_attention_status_t (struct hotplug_slot *slot, u_int8_t
*value);
typedef int get_latch_status_t  (struct hotplug_slot *slot, u_int8_t
*value);
typedef int get_adapter_status_t (struct hotplug_slot *slot, u_int8_t
*value);
typedef int get_address_t  (struct hotplug_slot *slot, u_int32_t *value);
typedef int get_max_bus_speed_t (struct hotplug_slot *slot, enum
pci_bus_speed *value);
typedef int get_cur_bus_speed_t (struct hotplug_slot *slot, enum
pci_bus_speed *value);


struct hotplug_slot_ops {
 //struct module *owner;
 enable_slot_t  * enable_slot;
 disable_slot_t  *disable_slot;
 set_attention_status_t *set_attention_status;
 hardware_test_t *hardware_test;
 get_power_status_t *get_power_status;
 get_attention_status_t *get_attention_status;
 get_latch_status_t  *get_latch_status;
 get_adapter_status_t *get_adapter_status;
 get_address_t  *get_address;
 get_max_bus_speed_t *get_max_bus_speed;
 get_cur_bus_speed_t *get_cur_bus_speed;
};

/**
 * struct hotplug_slot_info - used to notify the hotplug pci core of the
state of the slot
 * _at_power: if power is enabled or not (1/0)
 * _at_attention_status: if the attention light is enabled or not (1/0)
 * _at_latch_status: if the latch (if any) is open or closed (1/0)
 * _at_adapter_present: if there is a pci board present in the slot or not
(1/0)
 * _at_address: (domain << 16 | bus << 8 | dev)
 *
 * Used to notify the hotplug pci core of the status of a specific slot.
 */

struct hotplug_slot_info {
 u_int8_t power_status;
 u_int8_t attention_status;
 u_int8_t latch_status;
 u_int8_t adapter_status;
 u_int32_t address;
 enum pci_bus_speed max_bus_speed;
 enum pci_bus_speed cur_bus_speed;
};

/**
 * struct hotplug_slot - used to register a physical slot with the hotplug
pci core
 * _at_name: the name of the slot being registered.  This string must
 * be unique amoung slots registered on this system.
 * _at_ops: pointer to the &struct hotplug_slot_ops to be used for this slot
 * _at_info: pointer to the &struct hotplug_slot_info for the inital values for
 * this slot.
 * _at_private: used by the hotplug pci controller driver to store whatever it
 * needs.
 */
typedef void release_t (struct hotplug_slot *slot);
struct  hotplug_slot {
 char    *name;
 int     unit;
 struct hotplug_slot_ops  *ops;
 struct hotplug_slot_info *info;
 release_t * release;
 void   *private;
 /* Variables below this are for use only by the hotplug pci core.
 for example :pci_hotplug_slot_list
 */
 struct list_head  slot_list;
 //WB//struct kobject   kobj;
};
//WB//#define to_hotplug_slot(n) container_of(n, struct hotplug_slot, kobj)

#define LIST_HEAD_INIT(name) { &(name), &(name) }
#define LIST_HEAD(name) \
 struct list_head name = LIST_HEAD_INIT(name)

 /* list_entry - get the struct for this entry
 * _at_ptr:     the &struct list_head pointer.
 * _at_type:    the type of the struct this is embedded in.
 * _at_member:    the name of the list_struct within the struct.
 entry2 inorder to differ from the vm one
 */
#define list_entry2(ptr, type, member) \
 ((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member)))

 /**
 * list_for_each_safe - iterate over a list safe against removal of list
entry
 * _at_pos: the &struct list_head to use as a loop counter.
 * _at_n:  another &struct list_head to use as temporary storage
 * _at_head: the head for your list.
 */
#define list_for_each_safe2(pos, n, head) \
 for (pos = (head)->next, n = pos->next; pos != (head); \
 pos = n, n = pos->next)



extern int pci_hp_register  (struct hotplug_slot *slot);
extern int pci_hp_deregister  (struct hotplug_slot *slot);
extern int pci_hp_change_slot_info (struct hotplug_slot *slot,
    struct hotplug_slot_info *info);
//WB//extern struct subsystem pci_hotplug_slots_subsys;

#endif


///////////////////Makefile/////////////////////////////


.PATH: /usr/src/devdrv/

KMOD= fakeBSD
SRCS= fakeBSD.c pci_hotplug_core.c
SRCS+=  device_if.h bus_if.h pci_if.h
.include <bsd.kmod.mk>
Received on Mon May 08 2006 - 00:11:50 UTC

This archive was generated by hypermail 2.4.0 : Wed May 19 2021 - 11:38:55 UTC