LKML Archive on lore.kernel.org
help / color / mirror / Atom feed
* [PATCH] 2.4.10-ac8 PnP BIOS fix #1
@ 2001-10-08  1:47 Thomas Hood
  0 siblings, 0 replies; only message in thread
From: Thomas Hood @ 2001-10-08  1:47 UTC (permalink / raw)
  To: linux-kernel

Here is the first patch to 2.4.10-ac8 PnP BIOS driver.
It's the same one I described earlier, now against -ac8:

*  Clean up code formatting a bit more.
*  Move the pnpid32_to_pnpid() function earlier in the file,
      eliminating the need to declare it.
*  Break out of loops that scan nodes if an error is returned by
      get_dev_node.  This should be safer than ignoring the error
      or continuing on to the next node.
*  Fix bug in reporting of reserved resources (end of range too
      large by 1)
*  Fix bug in naming of requested regions that results in
      incorrect output from /proc/ioports
*  Allocate memory using pnp_bios_kmalloc() function ... so that
      error message is printed on failure
*  Cast args to u32 in call_pnp_bios() ... just to make sure.

// Thomas

The patch:
--- linux-2.4.10-ac8/drivers/pnp/pnp_bios.c	Sun Oct  7 14:38:45 2001
+++ linux-2.4.10-ac8-fix/drivers/pnp/pnp_bios.c	Sun Oct  7 15:37:29 2001
@@ -196,10 +196,10 @@
 		"popl %%edi\n\t"
 		"popl %%ebp\n\t"
 		: "=a" (status)
-		: "0" ((func) | (arg1 << 16)),
-		  "b" ((arg2) | (arg3 << 16)),
-		  "c" ((arg4) | (arg5 << 16)),
-		  "d" ((arg6) | (arg7 << 16)),
+		: "0" ((func) | (((u32)arg1) << 16)),
+		  "b" ((arg2) | (((u32)arg3) << 16)),
+		  "c" ((arg4) | (((u32)arg5) << 16)),
+		  "d" ((arg6) | (((u32)arg7) << 16)),
 		  "i" (PNP_CS32),
 		  "i" (0)
 		: "memory"
@@ -209,14 +209,24 @@
 	/* If we got here and this is set the pnp bios faulted on us.. */
 	if(pnp_bios_is_utter_crap)
 	{
-		printk(KERN_ERR "*** Warning: your PnP BIOS caused a fatal error. Attempting to continue\n");
-		printk(KERN_ERR "*** You may need to reboot with the \"nobiospnp\" option to operate stably\n");
-		printk(KERN_ERR "*** Check with your vendor for an updated BIOS\n");
+		printk(KERN_ERR "PnPBIOS: Warning! Your PnP BIOS caused a fatal error. Attempting to continue.\n");
+		printk(KERN_ERR "PnPBIOS: You may need to reboot with the \"nobiospnp\" option to operate stably.\n");
+		printk(KERN_ERR "PnPBIOS: Check with your vendor for an updated BIOS\n");
 	}
+
+//	if ( status ) printk(KERN_WARNING "PnPBIOS: BIOS returned error 0x%x from function 0x%x.\n", status, func);
 		
 	return status;
 }
 
+static void *pnp_bios_kmalloc(size_t size, int f)
+{
+	void *p = kmalloc( size, f );
+	if ( p == NULL )
+		printk(KERN_ERR "PnPBIOS: kmalloc() failed.\n");
+	return p;
+}
+
 /*
  *
  * PnP BIOS ACCESS FUNCTIONS
@@ -226,7 +236,6 @@
 /*
  * Call PnP BIOS with function 0x00, "get number of system device nodes"
  */
-
 int pnp_bios_dev_node_info(struct pnp_dev_node_info *data)
 {
 	u16 status;
@@ -252,7 +261,6 @@
  *               or volatile current (0) config
  * Output: *nodenum=next node or 0xff if no more nodes
  */
-
 int pnp_bios_get_dev_node(u8 *nodenum, char boot, struct pnp_bios_node *data)
 {
 	u16 status;
@@ -270,7 +278,6 @@
  *        boot = whether to set nonvolatile boot (!=0)
  *               or volatile current (0) config
  */
-
 int pnp_bios_set_dev_node(u8 nodenum, char boot, struct pnp_bios_node *data)
 {
 	u16 status;
@@ -314,7 +321,6 @@
 /*
  * Call PnP BIOS with function 0x05, "get docking station information"
  */
-
 static int pnp_bios_dock_station_info(struct pnp_docking_station_info *data)
 {
 	u16 status;
@@ -469,10 +475,10 @@
 	if (!current->fs->root) {
 		return -EAGAIN;
 	}
-	if (!(envp = (char **) kmalloc (20 * sizeof (char *), GFP_KERNEL))) {
+	if (!(envp = (char **) pnp_bios_kmalloc (20 * sizeof (char *), GFP_KERNEL))) {
 		return -ENOMEM;
 	}
-	if (!(buf = kmalloc (256, GFP_KERNEL))) {
+	if (!(buf = pnp_bios_kmalloc (256, GFP_KERNEL))) {
 		kfree (envp);
 		return -ENOMEM;
 	}
@@ -514,7 +520,6 @@
 /*
  * Poll the PnP docking at a regular interval
  */
- 
 static int pnp_dock_thread(void * unused)
 {
 	static struct pnp_docking_station_info now;
@@ -536,7 +541,6 @@
 
 		err = pnp_bios_dock_station_info(&now);
 
-
 		switch(err)
 		{
 			/*
@@ -551,7 +555,7 @@
 				d = 1;
 				break;
 			default:
-				printk(KERN_WARNING "dock: unexpected pnpbios error %d,\n", err);
+				printk(KERN_WARNING "PnPBIOS: Unexpected error 0x%x returned by BIOS.\n", err);
 				continue;
 		}
 		if(d != docked)
@@ -559,7 +563,7 @@
 			if(pnp_dock_event(d, &now)==0)
 			{
 				docked = d;
-//				printk(KERN_INFO "Docking station %stached.\n", docked?"at":"de");
+//				printk(KERN_INFO "PnPBIOS: Docking station %stached.\n", docked?"at":"de");
 			}
 		}
 	}	
@@ -596,7 +600,7 @@
 	}
 }
 
-static void __init pnpbios_add_ioresource(struct pci_dev *dev, int io, int len)
+static void inline pnpbios_add_ioresource(struct pci_dev *dev, int io, int len)
 {
 	int i = 0;
 	while (!(dev->resource[i].flags & IORESOURCE_UNSET) && i < DEVICE_COUNT_RESOURCE) i++;
@@ -607,19 +611,17 @@
 	}
 }
 
-static void __init pnpbios_add_memresource(struct pci_dev *dev, int io, int len)
+static void inline pnpbios_add_memresource(struct pci_dev *dev, int mem, int len)
 {
 	int i = 0;
 	while (!(dev->resource[i].flags & IORESOURCE_UNSET) && i < DEVICE_COUNT_RESOURCE) i++;
 	if (i < DEVICE_COUNT_RESOURCE) {
-		dev->resource[i].start = io;
-		dev->resource[i].end = io + len;
+		dev->resource[i].start = mem;
+		dev->resource[i].end = mem + len;
 		dev->resource[i].flags = IORESOURCE_MEM;  // Also clears _UNSET flag
 	}
 }
 
-static char * __init pnpid32_to_pnpid(u32 id);
-
 /*
  * request I/O ports which are used according to the PnP BIOS
  * to avoid I/O conflicts.
@@ -627,6 +629,7 @@
 static void mboard_request(char *pnpid, int io, int len)
 {
 	struct resource *res;
+	char *regionid;
     
 	if (
 		0 != strcmp(pnpid,"PNP0c01") &&  /* memory controller */
@@ -637,7 +640,7 @@
 
 	if (io < 0x100) {
 		/*
-		 * below 0x100 is only standard PC hardware
+		 * Below 0x100 is only standard PC hardware
 		 * (pics, kbd, timer, dma, ...)
 		 *
 		 * We should not get resource conflicts there,
@@ -648,22 +651,59 @@
 	}
 
 	/*
-	 * anything else we'll try reserve to avoid these ranges are
+	 * Anything else we'll try reserve to avoid these ranges are
 	 * assigned to someone (CardBus bridges for example) and thus are
 	 * triggering resource conflicts.
 	 *
-	 * failures at this point are usually harmless. pci quirks for
+	 * Failures at this point are usually harmless. pci quirks for
 	 * example do reserve stuff they know about too, so we might have
 	 * double reservations here.
+	 *
+	 * We really shouldn't just reserve these regions, though, since
+	 * that prevents the device drivers from claiming them.
 	 */
-	res = request_region(io,len,pnpid);
-	printk("PnPBIOS: %s: request 0x%x-0x%x%s\n",
-		pnpid,io,io+len,NULL != res ? " ok" : "");
+	regionid = pnp_bios_kmalloc(8, GFP_KERNEL);
+	if ( regionid == NULL )
+		return;
+	memcpy(regionid,pnpid,8);
+	res = request_region(io,len,regionid);
+	if ( res == NULL )
+		kfree( regionid );
+	printk(
+		"PnPBIOS: %s: 0x%x-0x%x %s reserved\n",
+		pnpid, io, io+len-1,
+		NULL != res ? "has been" : "was already"
+	);
 
 	return;
 }
 
-/* parse PNPBIOS "Allocated Resources Block" and fill IO,IRQ,DMA into pci_dev */
+
+#define HEX(id,a) hex[((id)>>a) & 15]
+#define CHAR(id,a) (0x40 + (((id)>>a) & 31))
+
+static char * __init pnpid32_to_pnpid(u32 id)
+{
+	const char *hex = "0123456789abcdef";
+	static char str[8];
+	id = be32_to_cpu(id);
+	str[0] = CHAR(id, 26);
+	str[1] = CHAR(id, 21);
+	str[2] = CHAR(id,16);
+	str[3] = HEX(id, 12);
+	str[4] = HEX(id, 8);
+	str[5] = HEX(id, 4);
+	str[6] = HEX(id, 0);
+	str[7] = '\0';
+	return str;
+}                                              
+
+#undef CHAR
+#undef HEX  
+
+/*
+ * parse PNPBIOS "Allocated Resources Block" and fill IO,IRQ,DMA into pci_dev
+ */
 static void __init pnpbios_rawdata_2_pci_dev(struct pnp_bios_node *node, struct pci_dev *dev)
 {
 	unsigned char *p = node->data, *lastp=NULL;
@@ -771,28 +811,6 @@
         return;
 }
 
-#define HEX(id,a) hex[((id)>>a) & 15]
-#define CHAR(id,a) (0x40 + (((id)>>a) & 31))
-
-static char * __init pnpid32_to_pnpid(u32 id)
-{
-	const char *hex = "0123456789abcdef";
-	static char str[8];
-	id = be32_to_cpu(id);
-	str[0] = CHAR(id, 26);
-	str[1] = CHAR(id, 21);
-	str[2] = CHAR(id,16);
-	str[3] = HEX(id, 12);
-	str[4] = HEX(id, 8);
-	str[5] = HEX(id, 4);
-	str[6] = HEX(id, 0);
-	str[7] = '\0';
-	return str;
-}                                              
-
-#undef CHAR
-#undef HEX  
-
 /*
  *
  * PnP BIOS PUBLIC DEVICE MANAGEMENT LAYER FUNCTIONS
@@ -836,16 +854,20 @@
 	if (pnp_bios_dev_node_info(&node_info) != 0)
 		return;
 
-	node = kmalloc(node_info.max_node_size, GFP_KERNEL);
+	node = pnp_bios_kmalloc(node_info.max_node_size, GFP_KERNEL);
 	if (!node)
 		return;
 
 	for(i=0,nodenum=0;i<0xff && nodenum!=0xff;i++) {
 		int thisnodenum = nodenum;
+		/* For now we build the list from the "boot" config
+		 * because asking for the "current" config causes
+		 * some BIOSes to crash.
+		 */
 		if (pnp_bios_get_dev_node((u8 *)&nodenum, (char )1 , node))
-			continue;
+			break;
 		nodes_got++;
-		dev =  kmalloc(sizeof (struct pci_dev), GFP_KERNEL);
+		dev =  pnp_bios_kmalloc(sizeof (struct pci_dev), GFP_KERNEL);
 		if (!dev)
 			break;
 		pnpbios_rawdata_2_pci_dev(node,dev);
@@ -1042,7 +1064,7 @@
 	spin_lock_init(&pnp_bios_lock);
 
 	if(pnp_bios_disabled) {
-		printk(KERN_INFO "PnPBIOS: driver disabled.\n");
+		printk(KERN_INFO "PnPBIOS: Disabled.\n");
 		return;
 	}
 
@@ -1062,14 +1084,13 @@
 		if (sum)
 			continue;
 		if (check->fields.version < 0x10) {
-			printk(KERN_WARNING "PnPBIOS: unsupported version %d.%d",
+			printk(KERN_WARNING "PnPBIOS: PnP BIOS version %d.%d is not supported.\n",
 			       check->fields.version >> 4,
 			       check->fields.version & 15);
 			continue;
 		}
-		printk(KERN_INFO "PnPBIOS: PnP BIOS installation structure at 0x%p\n",
-		       check);
-		printk(KERN_INFO "PnPBIOS: PnP BIOS version %d.%d, entry at 0x%x:0x%x, dseg at 0x%x\n",
+		printk(KERN_INFO "PnPBIOS: Found PnP BIOS installation structure at 0x%p.\n", check);
+		printk(KERN_INFO "PnPBIOS: PnP BIOS version %d.%d, entry 0x%x:0x%x, dseg 0x%x.\n",
                        check->fields.version >> 4, check->fields.version & 15,
 		       check->fields.pm16cseg, check->fields.pm16offset,
 		       check->fields.pm16dseg);
--- linux-2.4.10-ac8/drivers/pnp/pnp_proc.c	Sun Oct  7 14:38:45 2001
+++ linux-2.4.10-ac8-fix/drivers/pnp/pnp_proc.c	Sun Oct  7 15:37:29 2001
@@ -34,7 +34,8 @@
 	node = kmalloc(node_info.max_node_size, GFP_KERNEL);
 	if (!node) return -ENOMEM;
 	for (i=0,nodenum=0;i<0xff && nodenum!=0xff; i++) {
-		pnp_bios_get_dev_node(&nodenum, 1, node);
+		if ( pnp_bios_get_dev_node(&nodenum, 1, node) )
+			break;
 		p += sprintf(p, "%02x\t%08x\t%02x:%02x:%02x\t%04x\n",
 			     node->handle, node->eisa_id,
 			     node->type_code[0], node->type_code[1],
@@ -58,7 +59,8 @@
 	}
 	node = kmalloc(node_info.max_node_size, GFP_KERNEL);
 	if (!node) return -ENOMEM;
-	pnp_bios_get_dev_node(&nodenum, boot, node);
+	if ( pnp_bios_get_dev_node(&nodenum, boot, node) )
+		return -EIO;
 	len = node->size - sizeof(struct pnp_bios_node);
 	memcpy(buf, node->data, len);
 	kfree(node);
@@ -74,7 +76,8 @@
 
 	node = kmalloc(node_info.max_node_size, GFP_KERNEL);
 	if (!node) return -ENOMEM;
-	pnp_bios_get_dev_node(&nodenum, boot, node);
+	if ( pnp_bios_get_dev_node(&nodenum, boot, node) )
+		return -EIO;
 	if (count != node->size - sizeof(struct pnp_bios_node))
 		return -EINVAL;
 	memcpy(node->data, buf, count);


^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2001-10-08  1:48 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2001-10-08  1:47 [PATCH] 2.4.10-ac8 PnP BIOS fix #1 Thomas Hood

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