[parisc-linux-cvs] hardware.c and drivers.c changes

Helge Deller deller@gmx.de
Tue, 28 Aug 2001 10:04:36 +0200


On Tuesday 28 August 2001 10:01, Helge Deller wrote:
> CVSROOT:	/home/cvs/parisc
> Module name:	linux
> Changes by:	deller	01/08/28 02:01:28
>
> Modified files:
> 	arch/parisc/kernel: hardware.c drivers.c
>
> Log message:
> - switch to named initializers where possible,
> - switch the hardware database to __initdata (saves lots of memory later),
> - renamed a few functions:
> parisc_getHWtype	-> parisc_type_description
> parisc_getHWdescription -> parisc_hardware_description
> - removed parisc_get_reference(), use parisc_hardware_description() instead
> - initial SMP support for the pa_drivers list (hopefully correct :-))
> - only add a driver to the driver list if it really handles a device,
> - reduced MAX_DEVICES to 32 and added some sanity checks,
> - added many kerneldoc descriptions
> - don't reference the hardware database and copy the device name instead,


Index: hardware.c
===================================================================
RCS file: /home/cvs/parisc/linux/arch/parisc/kernel/hardware.c,v
retrieving revision 1.21
diff -u -r1.21 hardware.c
--- hardware.c	2001/08/14 16:54:52	1.21
+++ hardware.c	2001/08/28 07:54:08
@@ -30,32 +30,36 @@
 #include <asm/hardware.h>
 #include <linux/stddef.h>
 #include <linux/kernel.h>
+#include <linux/init.h>
 
-#define HPHW_NUM_TYPES 3431
+#define HPHW_NUM_TYPES 3431	
 
-static char * hw_type_name[16] = {
-	"Processor",
-	"Memory",
-	"B DMA",
-	"Obsolete",
-	"A DMA",
-	"A Direct",
-	"Obsolete",
-	"Bus Converter Port",
-	"HP CIO Adapter",
-	"Console",
-	"Foreign I/O Module",
-	"Bus Adapter",
-	"IOA (?)",
-	"Bus Bridge to Foreign Bus",
-	"HP Clothing: Fabric Component"
+static const char * hw_type_name[] = {
+	[HPHW_NPROC]	"Processor",
+	[HPHW_MEMORY]	"Memory",
+	[HPHW_B_DMA]	"B DMA",
+	[HPHW_OBSOLETE]	"Obsolete",
+	[HPHW_A_DMA]	"A DMA",
+	[HPHW_A_DIRECT]	"A Direct",
+	[HPHW_OTHER]	"Obsolete",
+	[HPHW_BCPORT]	"Bus Converter Port",
+	[HPHW_CIO]	"HP CIO Adapter",
+	[HPHW_CONSOLE]	"Console",
+	[HPHW_FIO]	"Foreign I/O Module",
+	[HPHW_BA]	"Bus Adapter",
+	[HPHW_IOA]	"IO Adapter",
+	[HPHW_BRIDGE]	"Bus Bridge to Foreign Bus",
+	[HPHW_FABRIC]	"HP Clothing: Fabric Component",
+	[HPHW_FAULTY]	"Faulty device"
 };
 
 /*
- *	XXX	Could this be __init ??
+ *	HP PARISC Hardware Database
+ *	Access to this database is only possible during bootup
+ *	so don't reference this table after starting the init process
  */
  
-static struct hp_hardware hp_hardware_list[] = {
+static struct hp_hardware hp_hardware_list[] __initdata = {
 	{HPHW_NPROC,0x01,0x4,0x0,"Indigo (840, 930)"},
 	{HPHW_NPROC,0x8,0x4,0x01,"Firefox(825,925)"},
 	{HPHW_NPROC,0xA,0x4,0x01,"Top Gun (835,834,935,635)"},
@@ -1335,7 +1339,7 @@
 	unsigned short model;
 	unsigned short mask;
 	enum cpu_type cpu;
-} hp_cpu_type_mask_list[] = {
+} hp_cpu_type_mask_list[] __initdata = {
 
 	{ 0x0000, 0x0ff0, pcx    },  /* 0x0000 - 0x000f */
 	{ 0x0048, 0x0ff0, pcxl   },  /* 0x0040 - 0x004f */
@@ -1419,7 +1423,8 @@
 	[pcxw_]	{ "PA8600 (PCX-W+)",	"2.0" }
 };
 
-char *parisc_getHWtype(unsigned short hw_type)
+const char *
+parisc_type_description(unsigned short hw_type)
 {
 	if (hw_type <= HPHW_CIO) {
 		return hw_type_name[hw_type];
@@ -1428,15 +1433,15 @@
 	}
 }
 
-char *parisc_getHWdescription(unsigned short hw_type, unsigned long hversion,
-		unsigned long sversion)
+const char * __init
+parisc_hardware_description(struct parisc_device_id *id)
 {
 	struct hp_hardware *listptr;
 	
 	for (listptr = hp_hardware_list; listptr->name; listptr++) {
-		if ((listptr->hw_type==hw_type) &&
-				(listptr->hversion==hversion) &&
-				(listptr->sversion==sversion)){
+		if ((listptr->hw_type == id->hw_type) &&
+				(listptr->hversion == id->hversion) &&
+				(listptr->sversion == id->sversion)){
 			return listptr->name;
 		}
 	}
@@ -1445,7 +1450,8 @@
 
 
 /* Interpret hversion (ret[0]) from PDC_MODEL(4)/PDC_MODEL_INFO(0) */
-enum cpu_type parisc_get_cpu_type(unsigned long hversion)
+enum cpu_type __init
+parisc_get_cpu_type(unsigned long hversion)
 {
 	struct hp_cpu_type_mask *ptr;
 	unsigned short model = ((unsigned short) (hversion)) >> 4;
@@ -1454,22 +1460,8 @@
 		if (ptr->model == (model & ptr->mask))
 			return ptr->cpu;
 	}
-	panic("parisc_get_cpu_type() could not identify CPU type\n");
+	panic("could not identify CPU type\n");
 
 	return pcx;	/* not reached: */
 }
 
-
-struct hp_hardware *parisc_get_reference(struct parisc_device_id *id)
-{
-	struct hp_hardware *listptr = hp_hardware_list;
-
-	for (listptr = hp_hardware_list; listptr->name; listptr++) {
-		if ((listptr->hw_type == id->hw_type) &&
-				(listptr->hversion == id->hversion) &&
-				(listptr->sversion == id->sversion)) {
-			return listptr;
-		}
-	}
-	return NULL;
-}
Index: drivers.c
===================================================================
RCS file: /home/cvs/parisc/linux/arch/parisc/kernel/drivers.c,v
retrieving revision 1.20
diff -u -r1.20 drivers.c
--- drivers.c	2001/08/24 14:45:03	1.20
+++ drivers.c	2001/08/28 07:54:08
@@ -8,6 +8,7 @@
  *
  * Copyright (c) 1999 The Puffin Group
  * Copyright (c) 2001 Matthew Wilcox for Hewlett Packard
+ * Copyright (c) 2001 Helge Deller <deller@gmx.de>
  * 
  * The file handles registering devices and drivers, then matching them.
  * It's the closest we get to a dating agency.
@@ -16,19 +17,25 @@
 #include <linux/slab.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
+#include <linux/spinlock.h>
+#include <linux/string.h>
 #include <asm/hardware.h>
 #include <asm/io.h>
 #include <asm/pdc.h>
 
 
-/* I'm assuming there'll never be 64 devices.  We should probably make
-   this more flexible.  */
+/* 
+ * I'm assuming there'll never be 32 devices.  We should probably make
+ * this more flexible.  
+ */
 
-#define MAX_DEVICES 64
+#define MAX_DEVICES 32
 
 static int num_devices;
 static struct parisc_device pa_devices[MAX_DEVICES];
 static struct parisc_driver *pa_drivers;
+static rwlock_t pa_lock = RW_LOCK_UNLOCKED;
+
 
 /**
  * match_device - Report whether this driver can handle this device
@@ -63,24 +70,22 @@
 
 }
 
+/**
+ * register_parisc_driver - Register this driver if it can handle a device
+ * @driver: the PA-RISC driver to try
+ */
 int register_parisc_driver(struct parisc_driver *driver)
 {
 	int i;
 
 	if (driver->next) {
-		BUG();
 		printk(KERN_WARNING "BUG: Skipping previously registered driver: %s %s\n",
 				driver->name, driver->version);
 		return 1;
 	}
 
-	/* link driver to the head of the global list.
-	 * The list gets built in reverse order...ideally, it shouldn't
-	 * matter but reality will eventually rear its ugly head.
-	 */
-	driver->next = pa_drivers;
-	pa_drivers = driver;
-
+	write_lock(&pa_lock);
+	
 	for (i=0; i < num_devices; i++) {
 		struct parisc_device *device = &pa_devices[i];
 
@@ -91,6 +96,16 @@
 
 		if (driver->probe(device) == 0) {
 			device->driver = driver;
+			
+			/* link driver to the head of the global list.
+			 * The list gets built in reverse order...ideally, it shouldn't
+			 * matter but reality will eventually rear its ugly head.
+			 */
+			if (!driver->next) {
+				driver->next = pa_drivers;
+				pa_drivers = driver;
+			}
+			
 		} else {
 			printk(KERN_WARNING "Warning : device (%d, 0x%x, 0x%x, 0x%x) NOT claimed by %s\n",
 				device->id.hw_type, device->id.hversion,
@@ -99,19 +114,23 @@
 		}
 	}
 
+	write_unlock(&pa_lock);
+
 	return 0;
 }
 
 
 
+/**
+ * unregister_parisc_driver - Unregister this driver from the list of drivers
+ * @driver: the PA-RISC driver to unregister
+ */
 int unregister_parisc_driver(struct parisc_driver *driver)
 {
 	int i;
+
+	write_lock(&pa_lock);
 
-/*
-** SMP_REVISIT: code is NOT SMP safe. Need to use a spinlock
-**      around *all* references to pa_drivers list.
-*/
 	if (pa_drivers == driver) {
 		/* was head of list - update head */
 		pa_drivers = driver->next;
@@ -122,12 +141,12 @@
 			prev = prev->next;
 		}
 
-		if (prev == NULL) {
+		if (!prev) {
 			printk(KERN_WARNING "unregister_parisc_driver: %s wasn't registered\n", driver->name);
 		} else {
 			/* Drop driver from list */
-			prev->next=driver->next;
-			driver->next=NULL;
+			prev->next = driver->next;
+			driver->next = NULL;
 		}
 
 	}
@@ -137,11 +156,32 @@
 			pa_devices[i].driver = NULL;
 	}
 
+	write_unlock(&pa_lock);
+
 	return 0;
 }
 
+
+/**
+ * get_num_pa_dev - Get the count of found devices
+ * (currently only used by the ccio driver)
+ */
+int get_num_pa_dev(void)
+{
+	int i;
+	
+	read_lock(&pa_lock);
+	i = num_devices;
+	read_unlock(&pa_lock);
+
+	return i;
+}
 
-/* this function adds an address to the list of additional addresses of a module */
+/**
+ * add_pa_dev_addr - Add an additional address to the list of addresses of a HP device
+ * @hp_device: the PA-RISC device structure
+ * @addr: the address to be added
+ */
 int add_pa_dev_addr(struct parisc_device *hp_device, unsigned long addr)
 {
 	if (!hp_device || !addr)
@@ -167,17 +207,31 @@
 	unsigned long bytecnt;
 	u8 iodc_data[32];
 	struct parisc_device *dev;
+	const char *name;
 
+	write_lock(&pa_lock);
+
 	/* Check to make sure this device has not already been added -Ryan */
 	for (i = 0; i < num_devices; i++) {
-		if (pa_devices[i].hpa == hpa)
+		if (pa_devices[i].hpa == hpa) {
+			write_unlock(&pa_lock);
 			return NULL;
+		}
 	}
 
+	if (num_devices >= MAX_DEVICES) {
+	    printk(KERN_ERR "%s: Too many devices.\n", __FUNCTION__ );
+	    write_unlock(&pa_lock);
+	    return NULL;
+	}
+	
 	dev = &pa_devices[num_devices];
+	memset(dev, 0, sizeof(*dev));
+	
 	status = pdc_iodc_read(&bytecnt, (void *)hpa, 0, &iodc_data, 32);
 	if (status != PDC_RET_OK) {
 		/* There is no device here, so we'll skip it */
+		write_unlock(&pa_lock);
 		return NULL;
 	}
 
@@ -187,69 +241,88 @@
 	dev->id.sversion = ((iodc_data[4] & 0x0f) << 16) |
 			(iodc_data[5] << 8) | iodc_data[6];
 	dev->hpa = hpa;
-	dev->driver = NULL;
-	dev->reference = parisc_get_reference(&dev->id);
+	name = parisc_hardware_description(&dev->id);
+	if (name) {
+		strncpy(dev->name, name, sizeof(dev->name)-1);
+	}
 
 	/* add the hpa of this module as the first additional address */
 	add_pa_dev_addr(dev, hpa);
 
 	num_devices++;
 
+	write_unlock(&pa_dev);
+
 	return dev;
 }
 
 /* Return status if device is managed */
 int register_pa_dev(struct parisc_device *hp_dev)
 {
-	struct parisc_driver *driver = pa_drivers;
+	struct parisc_driver *driver;
 
-	/* Locate a driver which agrees to manage this device.  */
-	while ((NULL == hp_dev->driver) && (NULL != driver)) {
+	if (!hp_dev)
+		return 0;
 
+	if (hp_dev->driver)
+		return 1;
+	
+	write_lock(&pa_lock);
+	
+	driver = pa_drivers;
+	
+	/* Locate a driver which agrees to manage this device.  */
+	while (driver) {
 		if (match_device(driver,hp_dev)) {
-			if (driver->probe(hp_dev) == 0)
+			if (driver->probe(hp_dev) == 0) {
 				hp_dev->driver = driver;
+				write_unlock(&pa_lock);
+				return 1;
+			}
 		}
 		driver = driver->next;
 	}
-
-	return (NULL != hp_dev->driver);
-}
 
-struct parisc_device *get_pa_dev(unsigned int index)
-{
-	if (index >= num_devices)
-	    return NULL;
+	write_unlock(&pa_lock);
 
-	return &pa_devices[index];
+	return 0;
 }
 
-inline int get_num_pa_dev()
-{
-	return num_devices;
-}
 
+/**
+ * print_pa_devices - Print out a list of devices found in this system
+ * @start_index: the starting index from which the list should be printed
+ * @num_indexes: the numbers of devices to print
+ */
 void print_pa_devices(int start_index, int num_indexes)
 {
-	int i;
+	unsigned int i;
 	struct parisc_device *d;
 
-	for(i = start_index; i < start_index + num_indexes; i++) {
+	read_lock(&pa_lock);
+	
+	for (i = start_index; i < start_index + num_indexes; i++) {
+		
+		if (i >= MAX_DEVICES)
+			break;
+		
 		d = &pa_devices[i];
+		
 		printk(KERN_INFO
 		"%d. %s (%d) at 0x%lx, versions 0x%x, 0x%x, 0x%x",
-		i + 1, (d->reference) ? d->reference->name : "Unknown device",
-		d->id.hw_type, d->hpa, d->id.hversion, d->id.hversion_rev,
-		d->id.sversion);
+		i + 1, d->name,	d->id.hw_type, d->hpa, 
+		d->id.hversion, d->id.hversion_rev, d->id.sversion);
 
 		if (d->num_addrs > 1) {
 			int k;
-			printk(KERN_INFO ",  additional addresses: ");
+			printk(",  additional addresses: ");
 			for (k = 1; k < d->num_addrs; k++)
-				printk(KERN_INFO "0x%lx ", d->addr[k]);
+				printk("0x%lx ", d->addr[k]);
 		}
 
-		printk(KERN_INFO "\n");
+		printk("\n");
 	}
+
+	read_unlock(&pa_lock);
 }