[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);
}