2001-10-13 15:41:32

by Thomas Hood

[permalink] [raw]
Subject: [PATCH] PnP BIOS -- bugfix; update devlist on setpnp

Okay, here's a new major patch to the PnP BIOS driver
which needs some testing before it's integrated.

Applies against 2.4.10-ac12, perhaps also against 2.4.11-ac1,
though I haven't tried.

Please test and let me know whether there are any problems.

Vaio users: Please make sure that this doesn't oops.
Others: Try using setpnp to change the current configuration.
Unload and reload the parport drivers to check that they
reinitialize with the updated resource information provided
by the PnP BIOS driver.

1) Fix bugs in resource reservation:
- end of reserved range too large by 1
- didn't reserve all system board resources
2) Change code so that set_dev_node updates the devlist, so
drivers loaded after a setpnp will get up-to-date resource
information. Because I haven't protected devlist update
code with locks, this feature isn't SMP safe yet. I'd like
some advice about how to do the locking. If you're worried,
don't use setpnp.
3) Miscellaneous code cleanups. Use "pnpbios" more consistently.
Improve printk output. Etc.

The patch:
--- linux-2.4.10-ac12/init/main.c Wed Oct 10 22:09:58 2001
+++ linux-2.4.10-ac12-fix/init/main.c Fri Oct 12 22:41:30 2001
@@ -824,7 +824,7 @@
isapnp_init();
#endif
#ifdef CONFIG_PNPBIOS
- pnp_bios_init();
+ pnpbios_init();
#endif

#ifdef CONFIG_TC
--- linux-2.4.10-ac12/include/linux/pnp_bios.h Wed Oct 10 22:09:57 2001
+++ linux-2.4.10-ac12-fix/include/linux/pnp_bios.h Sat Oct 13 09:57:24 2001
@@ -132,30 +132,35 @@
return (struct pnpbios_driver *)dev->driver;
}

-extern void pnp_bios_init (void);
-extern int pnp_bios_dev_node_info (struct pnp_dev_node_info *data);
-extern int pnp_bios_get_dev_node (u8 *nodenum, char config, struct pnp_bios_node *data);
-extern int pnp_bios_set_dev_node (u8 nodenum, char config, struct pnp_bios_node *data);
-extern int pnp_bios_get_event (u16 *message);
-extern int pnp_bios_send_message (u16 message);
-extern int pnp_bios_set_stat_res (char *info);
-extern int pnp_bios_get_stat_res (char *info);
-extern int pnp_bios_apm_id_table (char *table, u16 *size);
-extern int pnp_bios_isapnp_config (struct pnp_isa_config_struc *data);
-extern int pnp_bios_escd_info (struct escd_info_struc *data);
-extern int pnp_bios_read_escd (char *data, u32 nvram_base);
-extern int pnp_bios_write_escd (char *data, u32 nvram_base);
-
-extern void pnp_proc_init ( int dont_use_current );
-
#ifdef CONFIG_PNPBIOS
#define pnpbios_for_each_dev(dev) \
for(dev = pnpbios_dev_g(pnpbios_devices.next); dev != pnpbios_dev_g(&pnpbios_devices); dev = pnpbios_dev_g(dev->global_list.next))
-extern int pnp_bios_present (void);
+
+
+extern int pnpbios_dont_use_current_config;
+void *pnpbios_kmalloc(size_t size, int f);
+extern void pnpbios_init (void);
+extern void pnpbios_proc_init (void);
+
extern struct pci_dev *pnpbios_find_device(char *pnpid, struct pci_dev *dev);
-extern int pnpbios_register_driver(struct pnpbios_driver *drv);
+extern int pnpbios_register_driver(struct pnpbios_driver *drv);
extern void pnpbios_unregister_driver(struct pnpbios_driver *drv);

+extern int pnpbios_dev_node_info (struct pnp_dev_node_info *data);
+extern int pnpbios_get_dev_node (u8 *nodenum, char config, struct pnp_bios_node *data);
+extern int pnpbios_set_dev_node (u8 nodenum, char config, struct pnp_bios_node *data);
+#if needed
+extern int pnpbios_get_event (u16 *message);
+extern int pnpbios_send_message (u16 message);
+extern int pnpbios_set_stat_res (char *info);
+extern int pnpbios_get_stat_res (char *info);
+extern int pnpbios_apm_id_table (char *table, u16 *size);
+extern int pnpbios_isapnp_config (struct pnp_isa_config_struc *data);
+extern int pnpbios_escd_info (struct escd_info_struc *data);
+extern int pnpbios_read_escd (char *data, u32 nvram_base);
+extern int pnpbios_write_escd (char *data, u32 nvram_base);
+#endif
+
/*
* a helper function which helps ensure correct pnpbios_driver
* setup and cleanup for commonly-encountered hotplug/modular cases
@@ -189,24 +194,14 @@
return rc;
}

-#else
+#else /* CONFIG_PNPBIOS */
#define pnpbios_for_each_dev(dev) for(dev = NULL; 0; )

-static __inline__ int pnp_bios_present (void)
-{
- return 0;
-}
-
static __inline__ struct pci_dev *pnpbios_find_device(char *pnpid, struct pci_dev *dev)
{
return NULL;
}

-static __inline__ int pnpbios_module_init(struct pnpbios_driver *drv)
-{
- return -ENODEV;
-}
-
static __inline__ int pnpbios_register_driver(struct pnpbios_driver *drv)
{
return 0;
@@ -217,7 +212,12 @@
return;
}

-#endif
+static __inline__ int pnpbios_module_init(struct pnpbios_driver *drv)
+{
+ return -ENODEV;
+}
+
+#endif /* CONFIG_PNPBIOS */
#endif /* __KERNEL__ */

#endif /* _LINUX_PNP_BIOS_H */
--- linux-2.4.10-ac12/drivers/pnp/pnp_bios.c Wed Oct 10 22:09:19 2001
+++ linux-2.4.10-ac12-fix/drivers/pnp/pnp_bios.c Sat Oct 13 11:27:45 2001
@@ -50,11 +50,17 @@
#define PNP_SIGNATURE (('$' << 0) + ('P' << 8) + ('n' << 16) + ('P' << 24))

/*
+ * Forward declarations
+ */
+
+static void pnpbios_update_devlist( u8 nodenum, struct pnp_bios_node *data );
+
+/*
* This is the standard structure used to identify the entry point
* to the Plug and Play bios
*/
#pragma pack(1)
-union pnpbios {
+union pnp_bios_expansion_header {
struct {
u32 signature; /* "$PnP" */
u8 version; /* in BCD */
@@ -83,7 +89,7 @@
u16 segment;
} pnp_bios_callpoint;

-static union pnpbios * pnp_bios_inst_struc = NULL;
+static union pnp_bios_expansion_header * pnp_bios_hdr = NULL;

/* The PnP entries in the GDT */
#define PNP_GDT 0x0060
@@ -214,12 +220,16 @@
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)
+/*
+ *
+ * UTILITY FUNCTIONS
+ *
+ */
+
+void *pnpbios_kmalloc(size_t size, int f)
{
void *p = kmalloc( size, f );
if ( p == NULL )
@@ -228,18 +238,29 @@
}

/*
+ * Call this only after init time
+ */
+static int pnp_bios_is_present(void)
+{
+ return (pnp_bios_hdr != NULL);
+}
+
+/*
*
* PnP BIOS ACCESS FUNCTIONS
*
+ * pnp_bios_* are local functions used to call the BIOS
+ * pnpbios_* are the public interface to these functions
+ *
*/

/*
* Call PnP BIOS with function 0x00, "get number of system device nodes"
*/
-static int pnp_bios_dev_node_info_silently(struct pnp_dev_node_info *data)
+static int pnp_bios_dev_node_info(struct pnp_dev_node_info *data)
{
u16 status;
- if (!pnp_bios_present ())
+ if (!pnp_bios_is_present ())
return PNP_FUNCTION_NOT_SUPPORTED;
Q2_SET_SEL(PNP_TS1, data, sizeof(struct pnp_dev_node_info));
status = call_pnp_bios(PNP_GET_NUM_SYS_DEV_NODES, 0, PNP_TS1, 2, PNP_TS1, PNP_DS, 0, 0);
@@ -247,11 +268,11 @@
return status;
}

-int pnp_bios_dev_node_info(struct pnp_dev_node_info *data)
+int pnpbios_dev_node_info(struct pnp_dev_node_info *data)
{
- u16 status = pnp_bios_dev_node_info_silently( data );
+ int status = pnp_bios_dev_node_info( data );
if ( status )
- printk(KERN_WARNING "PnPBIOS: PnP BIOS dev_node_info function returned error status 0x%x\n", status);
+ printk(KERN_WARNING "PnPBIOS: dev_node_info: Unexpected status 0x%x\n", status);
return status;
}

@@ -269,22 +290,25 @@
* or volatile current (0) config
* Output: *nodenum=next node or 0xff if no more nodes
*/
-static int pnp_bios_get_dev_node_silently(u8 *nodenum, char boot, struct pnp_bios_node *data)
+static int pnp_bios_get_dev_node(u8 *nodenum, char boot, struct pnp_bios_node *data)
{
u16 status;
- if (!pnp_bios_present ())
- return PNP_FUNCTION_NOT_SUPPORTED;
Q2_SET_SEL(PNP_TS1, nodenum, sizeof(char));
Q2_SET_SEL(PNP_TS2, data, 64 * 1024);
status = call_pnp_bios(PNP_GET_SYS_DEV_NODE, 0, PNP_TS1, 0, PNP_TS2, boot ? 2 : 1, PNP_DS, 0);
return status;
}

-int pnp_bios_get_dev_node(u8 *nodenum, char boot, struct pnp_bios_node *data)
+int pnpbios_get_dev_node(u8 *nodenum, char boot, struct pnp_bios_node *data)
{
- u16 status = pnp_bios_get_dev_node_silently( nodenum, boot, data );
+ int status;
+ if (!pnp_bios_is_present ())
+ return PNP_FUNCTION_NOT_SUPPORTED;
+ if ( !boot & pnpbios_dont_use_current_config )
+ return PNP_FUNCTION_NOT_SUPPORTED;
+ status = pnp_bios_get_dev_node( nodenum, boot, data );
if ( status )
- printk(KERN_WARNING "PnPBIOS: PnP BIOS get_dev_node function returned error status 0x%x\n", status);
+ printk(KERN_WARNING "PnPBIOS: get_dev_node: Unexpected 0x%x\n", status);
return status;
}

@@ -294,21 +318,35 @@
* boot = whether to set nonvolatile boot (!=0)
* or volatile current (0) config
*/
-static int pnp_bios_set_dev_node_silently(u8 nodenum, char boot, struct pnp_bios_node *data)
+static int pnp_bios_set_dev_node(u8 nodenum, char boot, struct pnp_bios_node *data)
{
u16 status;
- if (!pnp_bios_present ())
- return PNP_FUNCTION_NOT_SUPPORTED;
Q2_SET_SEL(PNP_TS1, data, /* *((u16 *) data)*/ 65536);
status = call_pnp_bios(PNP_SET_SYS_DEV_NODE, nodenum, 0, PNP_TS1, boot ? 2 : 1, PNP_DS, 0, 0);
return status;
}

-int pnp_bios_set_dev_node(u8 nodenum, char boot, struct pnp_bios_node *data)
+int pnpbios_set_dev_node(u8 nodenum, char boot, struct pnp_bios_node *data)
{
- u16 status = pnp_bios_set_dev_node_silently( nodenum, boot, data );
- if ( status )
- printk(KERN_WARNING "PnPBIOS: PnP BIOS set_dev_node function returned error status 0x%x\n", status);
+ int status;
+ if (!pnp_bios_is_present ())
+ return PNP_FUNCTION_NOT_SUPPORTED;
+ if ( !boot & pnpbios_dont_use_current_config )
+ return PNP_FUNCTION_NOT_SUPPORTED;
+ status = pnp_bios_set_dev_node( nodenum, boot, data );
+ if ( status ) {
+ printk(KERN_WARNING "PnPBIOS: set_dev_node: Unexpected set_dev_node status 0x%x\n", status);
+ return status;
+ }
+ if ( !boot ) { /* Update devlist */
+ u8 thisnodenum = nodenum;
+ status = pnp_bios_get_dev_node( &nodenum, boot, data );
+ if ( status ) {
+ printk(KERN_WARNING "PnPBIOS: set_dev_node: Unexpected get_dev_node status 0x%x\n", status);
+ return status;
+ }
+ pnpbios_update_devlist( thisnodenum, data );
+ }
return status;
}

@@ -319,7 +357,7 @@
static int pnp_bios_get_event(u16 *event)
{
u16 status;
- if (!pnp_bios_present ())
+ if (!pnp_bios_is_present ())
return PNP_FUNCTION_NOT_SUPPORTED;
Q2_SET_SEL(PNP_TS1, event, sizeof(u16));
status = call_pnp_bios(PNP_GET_EVENT, 0, PNP_TS1, PNP_DS, 0, 0 ,0 ,0);
@@ -334,7 +372,7 @@
static int pnp_bios_send_message(u16 message)
{
u16 status;
- if (!pnp_bios_present ())
+ if (!pnp_bios_is_present ())
return PNP_FUNCTION_NOT_SUPPORTED;
status = call_pnp_bios(PNP_SEND_MESSAGE, message, PNP_DS, 0, 0, 0, 0, 0);
return status;
@@ -348,7 +386,7 @@
static int pnp_bios_dock_station_info(struct pnp_docking_station_info *data)
{
u16 status;
- if (!pnp_bios_present ())
+ if (!pnp_bios_is_present ())
return PNP_FUNCTION_NOT_SUPPORTED;
Q2_SET_SEL(PNP_TS1, data, sizeof(struct pnp_docking_station_info));
status = call_pnp_bios(PNP_GET_DOCKING_STATION_INFORMATION, 0, PNP_TS1, PNP_DS, 0, 0, 0, 0);
@@ -364,7 +402,7 @@
static int pnp_bios_set_stat_res(char *info)
{
u16 status;
- if (!pnp_bios_present ())
+ if (!pnp_bios_is_present ())
return PNP_FUNCTION_NOT_SUPPORTED;
Q2_SET_SEL(PNP_TS1, info, *((u16 *) info));
status = call_pnp_bios(PNP_SET_STATIC_ALLOCED_RES_INFO, 0, PNP_TS1, PNP_DS, 0, 0, 0, 0);
@@ -380,7 +418,7 @@
static int pnp_bios_get_stat_res(char *info)
{
u16 status;
- if (!pnp_bios_present ())
+ if (!pnp_bios_is_present ())
return PNP_FUNCTION_NOT_SUPPORTED;
Q2_SET_SEL(PNP_TS1, info, 64 * 1024);
status = call_pnp_bios(PNP_GET_STATIC_ALLOCED_RES_INFO, 0, PNP_TS1, PNP_DS, 0, 0, 0, 0);
@@ -395,7 +433,7 @@
static int pnp_bios_apm_id_table(char *table, u16 *size)
{
u16 status;
- if (!pnp_bios_present ())
+ if (!pnp_bios_is_present ())
return PNP_FUNCTION_NOT_SUPPORTED;
Q2_SET_SEL(PNP_TS1, table, *size);
Q2_SET_SEL(PNP_TS2, size, sizeof(u16));
@@ -411,7 +449,7 @@
static int pnp_bios_isapnp_config(struct pnp_isa_config_struc *data)
{
u16 status;
- if (!pnp_bios_present ())
+ if (!pnp_bios_is_present ())
return PNP_FUNCTION_NOT_SUPPORTED;
Q2_SET_SEL(PNP_TS1, data, sizeof(struct pnp_isa_config_struc));
status = call_pnp_bios(PNP_GET_PNP_ISA_CONFIG_STRUC, 0, PNP_TS1, PNP_DS, 0, 0, 0, 0);
@@ -426,7 +464,7 @@
static int pnp_bios_escd_info(struct escd_info_struc *data)
{
u16 status;
- if (!pnp_bios_present ())
+ if (!pnp_bios_is_present ())
return ESCD_FUNCTION_NOT_SUPPORTED;
Q2_SET_SEL(PNP_TS1, data, sizeof(struct escd_info_struc));
status = call_pnp_bios(PNP_GET_ESCD_INFO, 0, PNP_TS1, 2, PNP_TS1, 4, PNP_TS1, PNP_DS);
@@ -442,7 +480,7 @@
static int pnp_bios_read_escd(char *data, u32 nvram_base)
{
u16 status;
- if (!pnp_bios_present ())
+ if (!pnp_bios_is_present ())
return ESCD_FUNCTION_NOT_SUPPORTED;
Q2_SET_SEL(PNP_TS1, data, 64 * 1024);
set_base(gdt[PNP_TS2 >> 3], nvram_base);
@@ -459,7 +497,7 @@
static int pnp_bios_write_escd(char *data, u32 nvram_base)
{
u16 status;
- if (!pnp_bios_present ())
+ if (!pnp_bios_is_present ())
return ESCD_FUNCTION_NOT_SUPPORTED;
Q2_SET_SEL(PNP_TS1, data, 64 * 1024);
set_base(gdt[PNP_TS2 >> 3], nvram_base);
@@ -469,10 +507,6 @@
}
#endif

-EXPORT_SYMBOL(pnp_bios_dev_node_info);
-EXPORT_SYMBOL(pnp_bios_get_dev_node);
-EXPORT_SYMBOL(pnp_bios_set_dev_node);
-
/*
*
* PnP DOCKING FUNCTIONS
@@ -482,7 +516,6 @@
#ifdef CONFIG_HOTPLUG

static int unloading = 0;
-
static struct completion unload_sem;

/*
@@ -499,10 +532,10 @@
if (!current->fs->root) {
return -EAGAIN;
}
- if (!(envp = (char **) pnp_bios_kmalloc (20 * sizeof (char *), GFP_KERNEL))) {
+ if (!(envp = (char **) pnpbios_kmalloc (20 * sizeof (char *), GFP_KERNEL))) {
return -ENOMEM;
}
- if (!(buf = pnp_bios_kmalloc (256, GFP_KERNEL))) {
+ if (!(buf = pnpbios_kmalloc (256, GFP_KERNEL))) {
kfree (envp);
return -ENOMEM;
}
@@ -579,7 +612,7 @@
d = 1;
break;
default:
- printk(KERN_WARNING "PnPBIOS: Unexpected error 0x%x returned by BIOS.\n", err);
+ printk(KERN_WARNING "PnPBIOS: pnp_dock_thread: Unexpected status 0x%x returned by BIOS.\n", err);
continue;
}
if(d != docked)
@@ -587,7 +620,9 @@
if(pnp_dock_event(d, &now)==0)
{
docked = d;
-// printk(KERN_INFO "PnPBIOS: Docking station %stached.\n", docked?"at":"de");
+#if 0
+ printk(KERN_INFO "PnPBIOS: Docking station %stached.\n", docked?"at":"de");
+#endif
}
}
}
@@ -598,147 +633,62 @@

/*
*
- * NODE DATA HANDLING FUNCTIONS
+ * NODE DATA PARSING FUNCTIONS
*
*/

-static void inline pnpbios_add_irqresource(struct pci_dev *dev, int irq)
+static void pnpbios_add_irqresource(struct pci_dev *dev, int irq)
{
- // Permit irq==-1 which signifies "disabled"
int i = 0;
while (!(dev->irq_resource[i].flags & IORESOURCE_UNSET) && i < DEVICE_COUNT_IRQ) i++;
if (i < DEVICE_COUNT_IRQ) {
- dev->irq_resource[i].start = irq;
+ dev->irq_resource[i].start = (unsigned long) irq;
dev->irq_resource[i].flags = IORESOURCE_IRQ; // Also clears _UNSET flag
}
}

-static void inline pnpbios_add_dmaresource(struct pci_dev *dev, int dma)
+static void pnpbios_add_dmaresource(struct pci_dev *dev, int dma)
{
- // Permit dma==-1 which signifies "disabled"
int i = 0;
while (!(dev->dma_resource[i].flags & IORESOURCE_UNSET) && i < DEVICE_COUNT_DMA) i++;
if (i < DEVICE_COUNT_DMA) {
- dev->dma_resource[i].start = dma;
+ dev->dma_resource[i].start = (unsigned long) dma;
dev->dma_resource[i].flags = IORESOURCE_DMA; // Also clears _UNSET flag
}
}

-static void inline pnpbios_add_ioresource(struct pci_dev *dev, int io, int len)
+static void 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++;
if (i < DEVICE_COUNT_RESOURCE) {
- dev->resource[i].start = io;
- dev->resource[i].end = io + len;
+ dev->resource[i].start = (unsigned long) io;
+ dev->resource[i].end = (unsigned long)(io + len - 1);
dev->resource[i].flags = IORESOURCE_IO; // Also clears _UNSET flag
}
}

-static void inline pnpbios_add_memresource(struct pci_dev *dev, int mem, int len)
+static void 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 = mem;
- dev->resource[i].end = mem + len;
+ dev->resource[i].start = (unsigned long) mem;
+ dev->resource[i].end = (unsigned long)(mem + len - 1);
dev->resource[i].flags = IORESOURCE_MEM; // Also clears _UNSET flag
}
}

-/*
- * request I/O ports which are used according to the PnP BIOS
- * to avoid I/O conflicts.
- */
-static void mboard_request(char *pnpid, int io, int len)
-{
- struct resource *res;
- char *regionid;
-
- if (
- 0 != strcmp(pnpid,"PNP0c01") && /* memory controller */
- 0 != strcmp(pnpid,"PNP0c02") /* system peripheral: other */
- ) {
- return;
- }
-
- if (io < 0x100) {
- /*
- * Below 0x100 is only standard PC hardware
- * (pics, kbd, timer, dma, ...)
- *
- * We should not get resource conflicts there,
- * and the kernel reserves these anyway
- * (see arch/i386/kernel/setup.c).
- */
- return;
- }
-
- /*
- * 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
- * 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.
- */
- regionid = pnp_bios_kmalloc(16, GFP_KERNEL);
- if ( regionid == NULL )
- return;
- sprintf(regionid, "PnPBIOS %s", pnpid);
- 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;
-}
-
-
-#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)
+static void pnpbios_node_resource_data_to_dev(struct pnp_bios_node *node, struct pci_dev *dev)
{
unsigned char *p = node->data, *lastp=NULL;
int i;

/*
- * First, set dev contents to default values
+ * First, set resource info to default values
*/
- memset(dev,0,sizeof(struct pci_dev));
for (i=0;i<DEVICE_COUNT_RESOURCE;i++) {
- /* dev->resource[i].start = 0; */
+ dev->resource[i].start = 0; // "disabled"
dev->resource[i].flags = IORESOURCE_UNSET;
}
for (i=0;i<DEVICE_COUNT_IRQ;i++) {
@@ -751,7 +701,7 @@
}

/*
- * Fill in dev info
+ * Fill in dev resource info
*/
while ( (char *)p < ((char *)node->data + node->size )) {
if(p==lastp) break;
@@ -795,7 +745,7 @@
switch (p[0]>>3) {
case 0x04: // irq
{
- int i, mask, irq = -1; // "disabled"
+ int i, mask, irq = -1;
mask= p[1] + p[2]*256;
for (i=0;i<16;i++, mask=mask>>1)
if(mask & 0x01) irq=i;
@@ -804,7 +754,7 @@
}
case 0x05: // dma
{
- int i, mask, dma = -1; // "disabled"
+ int i, mask, dma = -1;
mask = p[1];
for (i=0;i<8;i++, mask = mask>>1)
if(mask & 0x01) dma=i;
@@ -816,7 +766,6 @@
int io= p[2] + p[3] *256;
int len = p[7];
pnpbios_add_ioresource(dev, io, len);
- mboard_request(pnpid32_to_pnpid(node->eisa_id),io,len);
break;
}
case 0x09: // fixed location io
@@ -843,42 +792,53 @@

static LIST_HEAD(pnpbios_devices);

-int pnp_bios_present(void)
-{
- return (pnp_bios_inst_struc != NULL);
-}
-
-EXPORT_SYMBOL(pnp_bios_present);
-
-static int __init pnpbios_insert_device(struct pci_dev *dev)
+static int inline pnpbios_insert_device(struct pci_dev *dev)
{
/* FIXME: Need to check for re-add of existing node */
list_add_tail(&dev->global_list, &pnpbios_devices);
return 0;
}

-/*
- * Build the list of pci_dev objects from the PnP table
- */
-
+#define HEX(id,a) hex[((id)>>a) & 15]
+#define CHAR(id,a) (0x40 + (((id)>>a) & 31))
+//
+static void inline pnpid32_to_pnpid(u32 id, char *str)
+{
+ const char *hex = "0123456789abcdef";
+
+ 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;
+}
+//
+#undef CHAR
+#undef HEX
+
static void __init pnpbios_build_devlist(void)
{
int i;
int nodenum;
int nodes_got = 0;
+ int devs = 0;
struct pnp_bios_node *node;
struct pnp_dev_node_info node_info;
struct pci_dev *dev;
- char *pnpid;
-

- if (!pnp_bios_present ())
+ if (!pnp_bios_is_present ())
return;

if (pnp_bios_dev_node_info(&node_info) != 0)
return;

- node = pnp_bios_kmalloc(node_info.max_node_size, GFP_KERNEL);
+ node = pnpbios_kmalloc(node_info.max_node_size, GFP_KERNEL);
if (!node)
return;

@@ -891,22 +851,45 @@
if (pnp_bios_get_dev_node((u8 *)&nodenum, (char )1 , node))
break;
nodes_got++;
- dev = pnp_bios_kmalloc(sizeof (struct pci_dev), GFP_KERNEL);
+ dev = pnpbios_kmalloc(sizeof (struct pci_dev), GFP_KERNEL);
if (!dev)
break;
- pnpbios_rawdata_2_pci_dev(node,dev);
+ memset(dev,0,sizeof(struct pci_dev));
dev->devfn=thisnodenum;
- pnpid = pnpid32_to_pnpid(node->eisa_id);
memcpy(dev->name,"PNPBIOS",8);
- memcpy(dev->slot_name,pnpid,8);
+ pnpid32_to_pnpid(node->eisa_id,dev->slot_name);
+ pnpbios_node_resource_data_to_dev(node,dev);
if(pnpbios_insert_device(dev)<0)
kfree(dev);
+ devs++;
}
kfree(node);

- printk(KERN_INFO "PnPBIOS: %i node%s reported by PnP BIOS\n", nodes_got, nodes_got != 1 ? "s" : "");
+ printk(KERN_INFO "PnPBIOS: %i node%s reported by PnP BIOS; %i recorded by driver.\n",
+ nodes_got, nodes_got != 1 ? "s" : "", devs);
}

+static struct pci_dev *pnpbios_find_device_by_nodenum( u8 nodenum )
+{
+ struct pci_dev *dev;
+
+ pnpbios_for_each_dev(dev) {
+ if(dev->devfn == nodenum)
+ return dev;
+ }
+
+ return NULL;
+}
+
+static void pnpbios_update_devlist( u8 nodenum, struct pnp_bios_node *data )
+{
+ struct pci_dev *dev = pnpbios_find_device_by_nodenum( nodenum );
+ if ( dev ) {
+ pnpbios_node_resource_data_to_dev(data,dev);
+ }
+
+ return;
+}

/*
*
@@ -920,22 +903,19 @@
struct pci_dev *pnpbios_find_device(char *pnpid, struct pci_dev *prev)
{
struct pci_dev *dev;
- int num;
-
- if(prev==NULL)
- num=0; /* Start from beginning */
- else
- num=prev->devfn + 1; /* Encode node number here */
+ int nodenum;

+ nodenum = 0;
+ if(prev)
+ nodenum=prev->devfn + 1; /* Encode node number here */

- pnpbios_for_each_dev(dev)
- {
- if(dev->devfn >= num)
- {
+ pnpbios_for_each_dev(dev) {
+ if(dev->devfn >= nodenum) {
if(memcmp(dev->slot_name, pnpid, 7)==0)
return dev;
}
}
+
return NULL;
}

@@ -1049,54 +1029,145 @@

EXPORT_SYMBOL(pnpbios_unregister_driver);

+/*
+ *
+ * RESOURCE RESERVATION FUNCTIONS
+ *
+ */
+
+static void __init pnpbios_reserve_resource_range(char *pnpid, int start, int end)
+{
+ struct resource *res;
+ char *regionid;
+
+ regionid = pnpbios_kmalloc(16, GFP_KERNEL);
+ if ( regionid == NULL )
+ return;
+ sprintf(regionid, "PnPBIOS %s", pnpid);
+ res = request_region(start,end-start+1,regionid);
+ if ( res == NULL )
+ kfree( regionid );
+ /*
+ * Failures at this point are usually harmless. pci quirks for
+ * example do reserve stuff they know about too, so we may well
+ * have double reservations.
+ */
+ printk(
+ "PnPBIOS: %s: 0x%x-0x%x %s reserved\n",
+ pnpid, start, end,
+ NULL != res ? "has been" : "was already"
+ );
+
+ return;
+}
+
+static void __init pnpbios_reserve_resources_of_dev( struct pci_dev *dev )
+{
+ int i;
+
+ for (i=0;i<DEVICE_COUNT_RESOURCE;i++) {
+ if ( dev->resource[i].flags & IORESOURCE_UNSET )
+ /* resource record not used */
+ break;
+ if ( dev->resource[i].start == 0 )
+ /* resource disabled */
+ continue;
+ if ( dev->resource[i].start < 0x100 )
+ /*
+ * Below 0x100 is only standard PC hardware
+ * (pics, kbd, timer, dma, ...)
+ *
+ * We should not get resource conflicts there,
+ * and the kernel reserves these anyway
+ * (see arch/i386/kernel/setup.c).
+ */
+ continue;
+ if ( dev->resource[i].end < dev->resource[i].start )
+ /* insane */
+ continue;
+ pnpbios_reserve_resource_range(
+ dev->slot_name,
+ dev->resource[i].start,
+ dev->resource[i].end
+ );
+ }
+
+ return;
+}
+
+/*
+ * Reserve resources used by system board devices
+ *
+ * We really shouldn't just _reserve_ these regions since
+ * that prevents the device drivers from claiming them.
+ */
+static void __init pnpbios_reserve_resources( void )
+{
+ struct pci_dev *dev;
+
+ pnpbios_for_each_dev(dev) {
+ if (
+ 0 != strcmp(dev->slot_name,"PNP0c01") && /* memory controller */
+ 0 != strcmp(dev->slot_name,"PNP0c02") /* system peripheral: other */
+ ) {
+ continue;
+ }
+ pnpbios_reserve_resources_of_dev(dev);
+ }
+
+ return;
+}
+
/*
*
* INIT AND EXIT
*
*
- * Search the defined area (0xf0000-0xffff0) for a valid PnP BIOS
- * structure and, if one is found, sets up the selectors and
- * entry points
*/

extern int is_sony_vaio_laptop;

-static int pnp_bios_disabled;
-static int pnp_bios_dont_use_current_config;
+static int pnpbios_disabled;
+int pnpbios_dont_use_current_config;

-static int disable_pnp_bios(char *str)
+static int __init pnpbios_disable_pnp_bios(char *str)
{
- pnp_bios_disabled=1;
+ pnpbios_disabled=1;
return 0;
}

-static int disable_use_of_current_config(char *str)
+static int __init pnpbios_disable_use_of_current_config(char *str)
{
- pnp_bios_dont_use_current_config=1;
+ pnpbios_dont_use_current_config=1;
return 0;
}

-__setup("nobiospnp", disable_pnp_bios);
-__setup("nobioscurrpnp", disable_use_of_current_config);
+__setup("nobiospnp", pnpbios_disable_pnp_bios);
+__setup("nobioscurrpnp", pnpbios_disable_use_of_current_config);

-void pnp_bios_init(void)
+void __init pnpbios_init(void)
{
- union pnpbios *check;
+ union pnp_bios_expansion_header *check;
u8 sum;
int i, length;

spin_lock_init(&pnp_bios_lock);

- if(pnp_bios_disabled) {
+ if(pnpbios_disabled) {
printk(KERN_INFO "PnPBIOS: Disabled.\n");
return;
}

if ( is_sony_vaio_laptop )
- pnp_bios_dont_use_current_config = 1;
+ pnpbios_dont_use_current_config = 1;

- for (check = (union pnpbios *) __va(0xf0000);
- check < (union pnpbios *) __va(0xffff0);
+ /*
+ * Search the defined area (0xf0000-0xffff0) for a valid PnP BIOS
+ * structure and, if one is found, sets up the selectors and
+ * entry points
+ */
+ for (check = (union pnp_bios_expansion_header *) __va(0xf0000);
+ check < (union pnp_bios_expansion_header *) __va(0xffff0);
((void *) (check)) += 16) {
if (check->fields.signature != PNP_SIGNATURE)
continue;
@@ -1123,12 +1194,14 @@
Q_SET_SEL(PNP_DS, check->fields.pm16dseg, 64 * 1024);
pnp_bios_callpoint.offset = check->fields.pm16offset;
pnp_bios_callpoint.segment = PNP_CS16;
- pnp_bios_inst_struc = check;
+ pnp_bios_hdr = check;
break;
}
+
pnpbios_build_devlist();
+ pnpbios_reserve_resources();
#ifdef CONFIG_PROC_FS
- pnp_proc_init( pnp_bios_dont_use_current_config );
+ pnpbios_proc_init();
#endif
#ifdef CONFIG_HOTPLUG
init_completion(&unload_sem);
@@ -1142,16 +1215,18 @@
MODULE_LICENSE("GPL");

/* We have to run it early and specifically in non modular.. */
-module_init(pnp_bios_init);
+module_init(pnpbios_init);

#ifdef CONFIG_HOTPLUG
-static void pnp_bios_exit(void)
+static void pnpbios_exit(void)
{
+ /* free_resources() ought to go here */
+ /* pnpbios_proc_done() */
unloading = 1;
wait_for_completion(&unload_sem);
}

-module_exit(pnp_bios_exit);
+module_exit(pnpbios_exit);

#endif
#endif
--- linux-2.4.10-ac12/drivers/pnp/pnp_proc.c Wed Oct 10 22:09:19 2001
+++ linux-2.4.10-ac12-fix/drivers/pnp/pnp_proc.c Sat Oct 13 08:42:05 2001
@@ -31,10 +31,10 @@
*eof = 1;
return 0;
}
- node = kmalloc(node_info.max_node_size, GFP_KERNEL);
+ node = pnpbios_kmalloc(node_info.max_node_size, GFP_KERNEL);
if (!node) return -ENOMEM;
for (i=0,nodenum=0;i<0xff && nodenum!=0xff; i++) {
- if ( pnp_bios_get_dev_node(&nodenum, 1, node) )
+ if ( pnpbios_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,
@@ -57,9 +57,9 @@
*eof = 1;
return 0;
}
- node = kmalloc(node_info.max_node_size, GFP_KERNEL);
+ node = pnpbios_kmalloc(node_info.max_node_size, GFP_KERNEL);
if (!node) return -ENOMEM;
- if ( pnp_bios_get_dev_node(&nodenum, boot, node) )
+ if ( pnpbios_get_dev_node(&nodenum, boot, node) )
return -EIO;
len = node->size - sizeof(struct pnp_bios_node);
memcpy(buf, node->data, len);
@@ -74,22 +74,25 @@
int boot = (long)data >> 8;
u8 nodenum = (long)data;

- node = kmalloc(node_info.max_node_size, GFP_KERNEL);
+ node = pnpbios_kmalloc(node_info.max_node_size, GFP_KERNEL);
if (!node) return -ENOMEM;
- if ( pnp_bios_get_dev_node(&nodenum, boot, node) )
+ if ( pnpbios_get_dev_node(&nodenum, boot, node) )
return -EIO;
if (count != node->size - sizeof(struct pnp_bios_node))
return -EINVAL;
memcpy(node->data, buf, count);
- if (pnp_bios_set_dev_node(node->handle, boot, node) != 0)
+ if (pnpbios_set_dev_node(node->handle, boot, node) != 0)
return -EINVAL;
kfree(node);
return count;
}

-static int pnp_proc_dont_use_current_config;
-
-void pnp_proc_init( int dont_use_current )
+/*
+ * When this is called, pnpbios functions are assumed to
+ * work and the pnpbios_dont_use_current_config flag
+ * should already have been set to the appropriate value
+ */
+void pnpbios_proc_init( void )
{
struct pnp_bios_node *node;
struct proc_dir_entry *ent;
@@ -97,10 +100,7 @@
int i;
u8 nodenum;

- pnp_proc_dont_use_current_config = dont_use_current;
-
- if (!pnp_bios_present()) return;
- if (pnp_bios_dev_node_info(&node_info) != 0) return;
+ if (pnpbios_dev_node_info(&node_info) != 0) return;

proc_pnp = proc_mkdir("pnp", proc_bus);
if (!proc_pnp) return;
@@ -108,13 +108,13 @@
if (!proc_pnp_boot) return;
create_proc_read_entry("devices", 0, proc_pnp, proc_read_devices, NULL);

- node = kmalloc(node_info.max_node_size, GFP_KERNEL);
+ node = pnpbios_kmalloc(node_info.max_node_size, GFP_KERNEL);
if (!node) return;
for (i=0,nodenum = 0; i<0xff && nodenum != 0xff; i++) {
- if (pnp_bios_get_dev_node(&nodenum, 1, node) != 0)
+ if (pnpbios_get_dev_node(&nodenum, 1, node) != 0)
break;
sprintf(name, "%02x", node->handle);
- if ( !pnp_proc_dont_use_current_config ) {
+ if ( !pnpbios_dont_use_current_config ) {
ent = create_proc_entry(name, 0, proc_pnp);
if (ent) {
ent->read_proc = proc_read_node;
@@ -132,7 +132,7 @@
kfree(node);
}

-void pnp_proc_done(void)
+void pnpbios_proc_done(void)
{
int i;
char name[3];
@@ -141,7 +141,7 @@

for (i=0; i<0xff; i++) {
sprintf(name, "%02x", i);
- if ( !pnp_proc_dont_use_current_config )
+ if ( !pnpbios_dont_use_current_config )
remove_proc_entry(name, proc_pnp);
remove_proc_entry(name, proc_pnp_boot);
}


2001-10-15 06:37:50

by Jurgen Botz

[permalink] [raw]
Subject: Re: [PATCH] PnP BIOS -- bugfix; update devlist on setpnp

Thomas Hood wrote:
> Okay, here's a new major patch to the PnP BIOS driver
> which needs some testing before it's integrated.
>[...]
> Vaio users: Please make sure that this doesn't oops.

Patched against 2.4.12-ac1, it works and doesn't oops my
VAIO PCG-N505VE.

-j


--
J?rgen Botz | While differing widely in the various
[email protected] | little bits we know, in our infinite
| ignorance we are all equal. -Karl Popper


2001-10-15 09:46:34

by Stelian Pop

[permalink] [raw]
Subject: Re: [PATCH] PnP BIOS -- bugfix; update devlist on setpnp

On Sun, Oct 14, 2001 at 11:37:39PM -0700, Jurgen Botz wrote:

> Thomas Hood wrote:
> > Okay, here's a new major patch to the PnP BIOS driver
> > which needs some testing before it's integrated.
> >[...]
> > Vaio users: Please make sure that this doesn't oops.
>
> Patched against 2.4.12-ac1, it works and doesn't oops my
> VAIO PCG-N505VE.

Same for me (against a 2.4.10-ac12), on a VAIO PCG-C1VE.

Relevant (maybe) output:

...
Sony Vaio laptop detected.
BIOS strings suggest APM reports battery life in minutes and wrong byte order.
PCI: PCI BIOS revision 2.10 entry at 0xfd98e, last bus=0
PCI: Using configuration type 1
PCI: Probing PCI hardware
PCI: Using IRQ router PIIX [8086/7110] at 00:07.0
PCI: Found IRQ 9 for device 00:08.0
PCI: Sharing IRQ 9 with 00:07.2
isapnp: Scanning for PnP cards...
isapnp: No Plug & Play device found
PnPBIOS: Found PnP BIOS installation structure at 0xc00f8120.
PnPBIOS: PnP BIOS version 1.0, entry 0xf0000:0xb25f, dseg 0x400.
PnPBIOS: 14 nodes reported by PnP BIOS; 14 recorded by driver.
PnPBIOS: PNP0c02: 0xfff80000-0xffffffff was already reserved
PnPBIOS: PNP0c02: 0xfff7f600-0xfff7ffff was already reserved
PnPBIOS: PNP0c02: 0x398-0x399 has been reserved
PnPBIOS: PNP0c02: 0x4d0-0x4d1 has been reserved
PnPBIOS: PNP0c02: 0x8000-0x804f was already reserved
PnPBIOS: PNP0c02: 0x1040-0x104f has been reserved
PnPBIOS: PNP0c01: 0xe8000-0xfffff was already reserved
PnPBIOS: PNP0c01: 0x100000-0x70ffbff was already reserved
PnPBIOS: PNP0c02: 0xdc000-0xdffff was already reserved
PnPBIOS: PNP0c02: 0xd1000-0xd3fff was already reserved
Linux NET4.0 for Linux 2.4
...

Stelian.
--
Stelian Pop <[email protected]>
|---------------- Free Software Engineer -----------------|
| Alc?ve - http://www.alcove.com - Tel: +33 1 49 22 68 00 |
|------------- Alc?ve, liberating software ---------------|

2001-10-15 12:00:49

by Andrey Panin

[permalink] [raw]
Subject: Re: [PATCH] PnP BIOS -- bugfix; update devlist on setpnp

On Mon, Oct 15, 2001 at 11:45:56AM +0200, Stelian Pop wrote:

> On Sun, Oct 14, 2001 at 11:37:39PM -0700, Jurgen Botz wrote:
>
> > Thomas Hood wrote:
> > > Okay, here's a new major patch to the PnP BIOS driver
> > > which needs some testing before it's integrated.
> > >[...]
> > > Vaio users: Please make sure that this doesn't oops.
> >
> > Patched against 2.4.12-ac1, it works and doesn't oops my
> > VAIO PCG-N505VE.
>
> Same for me (against a 2.4.10-ac12), on a VAIO PCG-C1VE.
>
> Relevant (maybe) output:
>
> ...
> Sony Vaio laptop detected.
> BIOS strings suggest APM reports battery life in minutes and wrong byte order.
> PCI: PCI BIOS revision 2.10 entry at 0xfd98e, last bus=0
> PCI: Using configuration type 1
> PCI: Probing PCI hardware
> PCI: Using IRQ router PIIX [8086/7110] at 00:07.0
> PCI: Found IRQ 9 for device 00:08.0
> PCI: Sharing IRQ 9 with 00:07.2
> isapnp: Scanning for PnP cards...
> isapnp: No Plug & Play device found
> PnPBIOS: Found PnP BIOS installation structure at 0xc00f8120.
> PnPBIOS: PnP BIOS version 1.0, entry 0xf0000:0xb25f, dseg 0x400.
> PnPBIOS: 14 nodes reported by PnP BIOS; 14 recorded by driver.
> PnPBIOS: PNP0c02: 0xfff80000-0xffffffff was already reserved
^^^^^^^^^^^^^^^^^^^^^
Looks wrong for me, we are trying to reserve _memory_ range with request_region().
Patch attached.

> PnPBIOS: PNP0c02: 0xfff7f600-0xfff7ffff was already reserved
> PnPBIOS: PNP0c02: 0x398-0x399 has been reserved
> PnPBIOS: PNP0c02: 0x4d0-0x4d1 has been reserved
> PnPBIOS: PNP0c02: 0x8000-0x804f was already reserved
> PnPBIOS: PNP0c02: 0x1040-0x104f has been reserved
> PnPBIOS: PNP0c01: 0xe8000-0xfffff was already reserved
> PnPBIOS: PNP0c01: 0x100000-0x70ffbff was already reserved
> PnPBIOS: PNP0c02: 0xdc000-0xdffff was already reserved
> PnPBIOS: PNP0c02: 0xd1000-0xd3fff was already reserved
> Linux NET4.0 for Linux 2.4
> ...
>
> Stelian.

--
Andrey Panin | Embedded systems software engineer
[email protected] | PGP key: http://www.orbita1.ru/~pazke/AndreyPanin.asc


Attachments:
(No filename) (0.00 B)
(No filename) (232.00 B)
Download all attachments

2001-10-15 12:19:42

by Alan

[permalink] [raw]
Subject: Re: [PATCH] PnP BIOS -- bugfix; update devlist on setpnp

> ^^^^^^^^^^^^^^^^^^^^^
> Looks wrong for me, we are trying to reserve _memory_ range with request_re=
> gion().

We should be creating memory and I/O regions as unused but exist rather than
requesting them as owned. We do want to reserve memory regions as present
but unused to void assigning PCI devices over them

2001-10-15 14:16:16

by Ion Badulescu

[permalink] [raw]
Subject: Re: [PATCH] PnP BIOS -- bugfix; update devlist on setpnp

On 13 Oct 2001, Thomas Hood wrote:

> Vaio users: Please make sure that this doesn't oops.
> Others: Try using setpnp to change the current configuration.
> Unload and reload the parport drivers to check that they
> reinitialize with the updated resource information provided
> by the PnP BIOS driver.

Works here on the inspiron 5k. Parport detects its config correctly, even
after multiple loads/unloads, lspnp and setpnp seem to be doing the right
thing, parport detects the new parameters after changing them with setpnp.

Relevant dmesg output:

PnPBIOS: Found PnP BIOS installation structure at 0xc00f7230.
PnPBIOS: PnP BIOS version 1.0, entry 0xf0000:0xa610, dseg 0x400.
PnPBIOS: 17 nodes reported by PnP BIOS; 17 recorded by driver.
PnPBIOS: PNP0c02: 0xfff80000-0xffffffff was already reserved
PnPBIOS: PNP0c01: 0xe8000-0xfffff was already reserved
PnPBIOS: PNP0c01: 0x100000-0xbffffff was already reserved
PnPBIOS: PNP0c02: 0x4d0-0x4d1 has been reserved
PnPBIOS: PNP0c02: 0x1000-0x103f has been reserved
PnPBIOS: PNP0c02: 0x1040-0x104f has been reserved
SBF: ACPI BOOT descriptor is wrong length (39)
SBF: Simple Boot Flag extension found and enabled.
SBF: Setting boot flags 0x1
parport: PnP BIOS reports device PNPBIOS PNP0401 (node number 0x16) is
configured to use io 0x0378, io 0x0778, irq 7, dma 3
[and then after 'setpnp 16 dma 1']
parport: PnP BIOS reports device PNPBIOS PNP0401 (node number 0x16) is
configured to use io 0x0378, io 0x0778, irq 7, dma 1

Thanks,
Ion

--
It is better to keep your mouth shut and be thought a fool,
than to open it and remove all doubt.

2001-10-15 21:51:11

by Thomas Hood

[permalink] [raw]
Subject: Re: [PATCH] PnP BIOS -- bugfix; update devlist on setpnp

On Mon, 2001-10-15 at 08:25, Alan Cox wrote:
> Andrey Panin wrote:
> > Looks wrong for me, we are trying to reserve _memory_ range with request_re=
> > gion().
>
> We should be creating memory and I/O regions as unused but exist rather than
> requesting them as owned. We do want to reserve memory regions as present
> but unused to void assigning PCI devices over them

Yes, we should.

The patch I submitted does not address that issue. It addresses
the issue of runtime devlist updating (plus the other small things
mentioned in my changelog), which is a big enough deal on its own.
Here's the changelog again for your reference:

1) Fix bugs in resource reservation:
- end of reserved range off by +1
- didn't reserve _all_ system board resources
2) Change code so that set_dev_node updates the devlist, so
drivers loaded after a setpnp will get up-to-date resource
information. Because I haven't protected devlist update
code with locks, this feature isn't SMP safe yet.
3) Miscellaneous code cleanups. Use "pnpbios" more consistently.
Improve printk output. Etc.

Alan: I think the patch can go in as-is, since the much-appreciated
beta testers report no calamities. :) I append it here: it applies
correctly to 2.4.12-ac2 with one hunk offset by two lines.

As noted in (2), however, the patched driver allows updating of
the devlist even though it doesn't use any locks; so I conclude
that the code isn't SMP safe as it is. My secret wish is that
someone else will submit a patch for this, because I'm aware that
my understanding of SMP issues isn't really adequate.

The "flag as present but unused" issue can be addressed in a future
patch. Once again, if someone wants to submit that patch
they're very welcome to do so. Otherwise it'll have to wait for
me to figure out exactly what Alan means. ;)

--
Thomas

The patch again:
--- linux-2.4.10-ac12/init/main.c Wed Oct 10 22:09:58 2001
+++ linux-2.4.10-ac12-fix/init/main.c Fri Oct 12 22:41:30 2001
@@ -824,7 +824,7 @@
isapnp_init();
#endif
#ifdef CONFIG_PNPBIOS
- pnp_bios_init();
+ pnpbios_init();
#endif

#ifdef CONFIG_TC
--- linux-2.4.10-ac12/include/linux/pnp_bios.h Wed Oct 10 22:09:57 2001
+++ linux-2.4.10-ac12-fix/include/linux/pnp_bios.h Sat Oct 13 09:57:24 2001
@@ -132,30 +132,35 @@
return (struct pnpbios_driver *)dev->driver;
}

-extern void pnp_bios_init (void);
-extern int pnp_bios_dev_node_info (struct pnp_dev_node_info *data);
-extern int pnp_bios_get_dev_node (u8 *nodenum, char config, struct pnp_bios_node *data);
-extern int pnp_bios_set_dev_node (u8 nodenum, char config, struct pnp_bios_node *data);
-extern int pnp_bios_get_event (u16 *message);
-extern int pnp_bios_send_message (u16 message);
-extern int pnp_bios_set_stat_res (char *info);
-extern int pnp_bios_get_stat_res (char *info);
-extern int pnp_bios_apm_id_table (char *table, u16 *size);
-extern int pnp_bios_isapnp_config (struct pnp_isa_config_struc *data);
-extern int pnp_bios_escd_info (struct escd_info_struc *data);
-extern int pnp_bios_read_escd (char *data, u32 nvram_base);
-extern int pnp_bios_write_escd (char *data, u32 nvram_base);
-
-extern void pnp_proc_init ( int dont_use_current );
-
#ifdef CONFIG_PNPBIOS
#define pnpbios_for_each_dev(dev) \
for(dev = pnpbios_dev_g(pnpbios_devices.next); dev != pnpbios_dev_g(&pnpbios_devices); dev = pnpbios_dev_g(dev->global_list.next))
-extern int pnp_bios_present (void);
+
+
+extern int pnpbios_dont_use_current_config;
+void *pnpbios_kmalloc(size_t size, int f);
+extern void pnpbios_init (void);
+extern void pnpbios_proc_init (void);
+
extern struct pci_dev *pnpbios_find_device(char *pnpid, struct pci_dev *dev);
-extern int pnpbios_register_driver(struct pnpbios_driver *drv);
+extern int pnpbios_register_driver(struct pnpbios_driver *drv);
extern void pnpbios_unregister_driver(struct pnpbios_driver *drv);

+extern int pnpbios_dev_node_info (struct pnp_dev_node_info *data);
+extern int pnpbios_get_dev_node (u8 *nodenum, char config, struct pnp_bios_node *data);
+extern int pnpbios_set_dev_node (u8 nodenum, char config, struct pnp_bios_node *data);
+#if needed
+extern int pnpbios_get_event (u16 *message);
+extern int pnpbios_send_message (u16 message);
+extern int pnpbios_set_stat_res (char *info);
+extern int pnpbios_get_stat_res (char *info);
+extern int pnpbios_apm_id_table (char *table, u16 *size);
+extern int pnpbios_isapnp_config (struct pnp_isa_config_struc *data);
+extern int pnpbios_escd_info (struct escd_info_struc *data);
+extern int pnpbios_read_escd (char *data, u32 nvram_base);
+extern int pnpbios_write_escd (char *data, u32 nvram_base);
+#endif
+
/*
* a helper function which helps ensure correct pnpbios_driver
* setup and cleanup for commonly-encountered hotplug/modular cases
@@ -189,24 +194,14 @@
return rc;
}

-#else
+#else /* CONFIG_PNPBIOS */
#define pnpbios_for_each_dev(dev) for(dev = NULL; 0; )

-static __inline__ int pnp_bios_present (void)
-{
- return 0;
-}
-
static __inline__ struct pci_dev *pnpbios_find_device(char *pnpid, struct pci_dev *dev)
{
return NULL;
}

-static __inline__ int pnpbios_module_init(struct pnpbios_driver *drv)
-{
- return -ENODEV;
-}
-
static __inline__ int pnpbios_register_driver(struct pnpbios_driver *drv)
{
return 0;
@@ -217,7 +212,12 @@
return;
}

-#endif
+static __inline__ int pnpbios_module_init(struct pnpbios_driver *drv)
+{
+ return -ENODEV;
+}
+
+#endif /* CONFIG_PNPBIOS */
#endif /* __KERNEL__ */

#endif /* _LINUX_PNP_BIOS_H */
--- linux-2.4.10-ac12/drivers/pnp/pnp_bios.c Wed Oct 10 22:09:19 2001
+++ linux-2.4.10-ac12-fix/drivers/pnp/pnp_bios.c Sat Oct 13 11:27:45 2001
@@ -50,11 +50,17 @@
#define PNP_SIGNATURE (('$' << 0) + ('P' << 8) + ('n' << 16) + ('P' << 24))

/*
+ * Forward declarations
+ */
+
+static void pnpbios_update_devlist( u8 nodenum, struct pnp_bios_node *data );
+
+/*
* This is the standard structure used to identify the entry point
* to the Plug and Play bios
*/
#pragma pack(1)
-union pnpbios {
+union pnp_bios_expansion_header {
struct {
u32 signature; /* "$PnP" */
u8 version; /* in BCD */
@@ -83,7 +89,7 @@
u16 segment;
} pnp_bios_callpoint;

-static union pnpbios * pnp_bios_inst_struc = NULL;
+static union pnp_bios_expansion_header * pnp_bios_hdr = NULL;

/* The PnP entries in the GDT */
#define PNP_GDT 0x0060
@@ -214,12 +220,16 @@
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)
+/*
+ *
+ * UTILITY FUNCTIONS
+ *
+ */
+
+void *pnpbios_kmalloc(size_t size, int f)
{
void *p = kmalloc( size, f );
if ( p == NULL )
@@ -228,18 +238,29 @@
}

/*
+ * Call this only after init time
+ */
+static int pnp_bios_is_present(void)
+{
+ return (pnp_bios_hdr != NULL);
+}
+
+/*
*
* PnP BIOS ACCESS FUNCTIONS
*
+ * pnp_bios_* are local functions used to call the BIOS
+ * pnpbios_* are the public interface to these functions
+ *
*/

/*
* Call PnP BIOS with function 0x00, "get number of system device nodes"
*/
-static int pnp_bios_dev_node_info_silently(struct pnp_dev_node_info *data)
+static int pnp_bios_dev_node_info(struct pnp_dev_node_info *data)
{
u16 status;
- if (!pnp_bios_present ())
+ if (!pnp_bios_is_present ())
return PNP_FUNCTION_NOT_SUPPORTED;
Q2_SET_SEL(PNP_TS1, data, sizeof(struct pnp_dev_node_info));
status = call_pnp_bios(PNP_GET_NUM_SYS_DEV_NODES, 0, PNP_TS1, 2, PNP_TS1, PNP_DS, 0, 0);
@@ -247,11 +268,11 @@
return status;
}

-int pnp_bios_dev_node_info(struct pnp_dev_node_info *data)
+int pnpbios_dev_node_info(struct pnp_dev_node_info *data)
{
- u16 status = pnp_bios_dev_node_info_silently( data );
+ int status = pnp_bios_dev_node_info( data );
if ( status )
- printk(KERN_WARNING "PnPBIOS: PnP BIOS dev_node_info function returned error status 0x%x\n", status);
+ printk(KERN_WARNING "PnPBIOS: dev_node_info: Unexpected status 0x%x\n", status);
return status;
}

@@ -269,22 +290,25 @@
* or volatile current (0) config
* Output: *nodenum=next node or 0xff if no more nodes
*/
-static int pnp_bios_get_dev_node_silently(u8 *nodenum, char boot, struct pnp_bios_node *data)
+static int pnp_bios_get_dev_node(u8 *nodenum, char boot, struct pnp_bios_node *data)
{
u16 status;
- if (!pnp_bios_present ())
- return PNP_FUNCTION_NOT_SUPPORTED;
Q2_SET_SEL(PNP_TS1, nodenum, sizeof(char));
Q2_SET_SEL(PNP_TS2, data, 64 * 1024);
status = call_pnp_bios(PNP_GET_SYS_DEV_NODE, 0, PNP_TS1, 0, PNP_TS2, boot ? 2 : 1, PNP_DS, 0);
return status;
}

-int pnp_bios_get_dev_node(u8 *nodenum, char boot, struct pnp_bios_node *data)
+int pnpbios_get_dev_node(u8 *nodenum, char boot, struct pnp_bios_node *data)
{
- u16 status = pnp_bios_get_dev_node_silently( nodenum, boot, data );
+ int status;
+ if (!pnp_bios_is_present ())
+ return PNP_FUNCTION_NOT_SUPPORTED;
+ if ( !boot & pnpbios_dont_use_current_config )
+ return PNP_FUNCTION_NOT_SUPPORTED;
+ status = pnp_bios_get_dev_node( nodenum, boot, data );
if ( status )
- printk(KERN_WARNING "PnPBIOS: PnP BIOS get_dev_node function returned error status 0x%x\n", status);
+ printk(KERN_WARNING "PnPBIOS: get_dev_node: Unexpected 0x%x\n", status);
return status;
}

@@ -294,21 +318,35 @@
* boot = whether to set nonvolatile boot (!=0)
* or volatile current (0) config
*/
-static int pnp_bios_set_dev_node_silently(u8 nodenum, char boot, struct pnp_bios_node *data)
+static int pnp_bios_set_dev_node(u8 nodenum, char boot, struct pnp_bios_node *data)
{
u16 status;
- if (!pnp_bios_present ())
- return PNP_FUNCTION_NOT_SUPPORTED;
Q2_SET_SEL(PNP_TS1, data, /* *((u16 *) data)*/ 65536);
status = call_pnp_bios(PNP_SET_SYS_DEV_NODE, nodenum, 0, PNP_TS1, boot ? 2 : 1, PNP_DS, 0, 0);
return status;
}

-int pnp_bios_set_dev_node(u8 nodenum, char boot, struct pnp_bios_node *data)
+int pnpbios_set_dev_node(u8 nodenum, char boot, struct pnp_bios_node *data)
{
- u16 status = pnp_bios_set_dev_node_silently( nodenum, boot, data );
- if ( status )
- printk(KERN_WARNING "PnPBIOS: PnP BIOS set_dev_node function returned error status 0x%x\n", status);
+ int status;
+ if (!pnp_bios_is_present ())
+ return PNP_FUNCTION_NOT_SUPPORTED;
+ if ( !boot & pnpbios_dont_use_current_config )
+ return PNP_FUNCTION_NOT_SUPPORTED;
+ status = pnp_bios_set_dev_node( nodenum, boot, data );
+ if ( status ) {
+ printk(KERN_WARNING "PnPBIOS: set_dev_node: Unexpected set_dev_node status 0x%x\n", status);
+ return status;
+ }
+ if ( !boot ) { /* Update devlist */
+ u8 thisnodenum = nodenum;
+ status = pnp_bios_get_dev_node( &nodenum, boot, data );
+ if ( status ) {
+ printk(KERN_WARNING "PnPBIOS: set_dev_node: Unexpected get_dev_node status 0x%x\n", status);
+ return status;
+ }
+ pnpbios_update_devlist( thisnodenum, data );
+ }
return status;
}

@@ -319,7 +357,7 @@
static int pnp_bios_get_event(u16 *event)
{
u16 status;
- if (!pnp_bios_present ())
+ if (!pnp_bios_is_present ())
return PNP_FUNCTION_NOT_SUPPORTED;
Q2_SET_SEL(PNP_TS1, event, sizeof(u16));
status = call_pnp_bios(PNP_GET_EVENT, 0, PNP_TS1, PNP_DS, 0, 0 ,0 ,0);
@@ -334,7 +372,7 @@
static int pnp_bios_send_message(u16 message)
{
u16 status;
- if (!pnp_bios_present ())
+ if (!pnp_bios_is_present ())
return PNP_FUNCTION_NOT_SUPPORTED;
status = call_pnp_bios(PNP_SEND_MESSAGE, message, PNP_DS, 0, 0, 0, 0, 0);
return status;
@@ -348,7 +386,7 @@
static int pnp_bios_dock_station_info(struct pnp_docking_station_info *data)
{
u16 status;
- if (!pnp_bios_present ())
+ if (!pnp_bios_is_present ())
return PNP_FUNCTION_NOT_SUPPORTED;
Q2_SET_SEL(PNP_TS1, data, sizeof(struct pnp_docking_station_info));
status = call_pnp_bios(PNP_GET_DOCKING_STATION_INFORMATION, 0, PNP_TS1, PNP_DS, 0, 0, 0, 0);
@@ -364,7 +402,7 @@
static int pnp_bios_set_stat_res(char *info)
{
u16 status;
- if (!pnp_bios_present ())
+ if (!pnp_bios_is_present ())
return PNP_FUNCTION_NOT_SUPPORTED;
Q2_SET_SEL(PNP_TS1, info, *((u16 *) info));
status = call_pnp_bios(PNP_SET_STATIC_ALLOCED_RES_INFO, 0, PNP_TS1, PNP_DS, 0, 0, 0, 0);
@@ -380,7 +418,7 @@
static int pnp_bios_get_stat_res(char *info)
{
u16 status;
- if (!pnp_bios_present ())
+ if (!pnp_bios_is_present ())
return PNP_FUNCTION_NOT_SUPPORTED;
Q2_SET_SEL(PNP_TS1, info, 64 * 1024);
status = call_pnp_bios(PNP_GET_STATIC_ALLOCED_RES_INFO, 0, PNP_TS1, PNP_DS, 0, 0, 0, 0);
@@ -395,7 +433,7 @@
static int pnp_bios_apm_id_table(char *table, u16 *size)
{
u16 status;
- if (!pnp_bios_present ())
+ if (!pnp_bios_is_present ())
return PNP_FUNCTION_NOT_SUPPORTED;
Q2_SET_SEL(PNP_TS1, table, *size);
Q2_SET_SEL(PNP_TS2, size, sizeof(u16));
@@ -411,7 +449,7 @@
static int pnp_bios_isapnp_config(struct pnp_isa_config_struc *data)
{
u16 status;
- if (!pnp_bios_present ())
+ if (!pnp_bios_is_present ())
return PNP_FUNCTION_NOT_SUPPORTED;
Q2_SET_SEL(PNP_TS1, data, sizeof(struct pnp_isa_config_struc));
status = call_pnp_bios(PNP_GET_PNP_ISA_CONFIG_STRUC, 0, PNP_TS1, PNP_DS, 0, 0, 0, 0);
@@ -426,7 +464,7 @@
static int pnp_bios_escd_info(struct escd_info_struc *data)
{
u16 status;
- if (!pnp_bios_present ())
+ if (!pnp_bios_is_present ())
return ESCD_FUNCTION_NOT_SUPPORTED;
Q2_SET_SEL(PNP_TS1, data, sizeof(struct escd_info_struc));
status = call_pnp_bios(PNP_GET_ESCD_INFO, 0, PNP_TS1, 2, PNP_TS1, 4, PNP_TS1, PNP_DS);
@@ -442,7 +480,7 @@
static int pnp_bios_read_escd(char *data, u32 nvram_base)
{
u16 status;
- if (!pnp_bios_present ())
+ if (!pnp_bios_is_present ())
return ESCD_FUNCTION_NOT_SUPPORTED;
Q2_SET_SEL(PNP_TS1, data, 64 * 1024);
set_base(gdt[PNP_TS2 >> 3], nvram_base);
@@ -459,7 +497,7 @@
static int pnp_bios_write_escd(char *data, u32 nvram_base)
{
u16 status;
- if (!pnp_bios_present ())
+ if (!pnp_bios_is_present ())
return ESCD_FUNCTION_NOT_SUPPORTED;
Q2_SET_SEL(PNP_TS1, data, 64 * 1024);
set_base(gdt[PNP_TS2 >> 3], nvram_base);
@@ -469,10 +507,6 @@
}
#endif

-EXPORT_SYMBOL(pnp_bios_dev_node_info);
-EXPORT_SYMBOL(pnp_bios_get_dev_node);
-EXPORT_SYMBOL(pnp_bios_set_dev_node);
-
/*
*
* PnP DOCKING FUNCTIONS
@@ -482,7 +516,6 @@
#ifdef CONFIG_HOTPLUG

static int unloading = 0;
-
static struct completion unload_sem;

/*
@@ -499,10 +532,10 @@
if (!current->fs->root) {
return -EAGAIN;
}
- if (!(envp = (char **) pnp_bios_kmalloc (20 * sizeof (char *), GFP_KERNEL))) {
+ if (!(envp = (char **) pnpbios_kmalloc (20 * sizeof (char *), GFP_KERNEL))) {
return -ENOMEM;
}
- if (!(buf = pnp_bios_kmalloc (256, GFP_KERNEL))) {
+ if (!(buf = pnpbios_kmalloc (256, GFP_KERNEL))) {
kfree (envp);
return -ENOMEM;
}
@@ -579,7 +612,7 @@
d = 1;
break;
default:
- printk(KERN_WARNING "PnPBIOS: Unexpected error 0x%x returned by BIOS.\n", err);
+ printk(KERN_WARNING "PnPBIOS: pnp_dock_thread: Unexpected status 0x%x returned by BIOS.\n", err);
continue;
}
if(d != docked)
@@ -587,7 +620,9 @@
if(pnp_dock_event(d, &now)==0)
{
docked = d;
-// printk(KERN_INFO "PnPBIOS: Docking station %stached.\n", docked?"at":"de");
+#if 0
+ printk(KERN_INFO "PnPBIOS: Docking station %stached.\n", docked?"at":"de");
+#endif
}
}
}
@@ -598,147 +633,62 @@

/*
*
- * NODE DATA HANDLING FUNCTIONS
+ * NODE DATA PARSING FUNCTIONS
*
*/

-static void inline pnpbios_add_irqresource(struct pci_dev *dev, int irq)
+static void pnpbios_add_irqresource(struct pci_dev *dev, int irq)
{
- // Permit irq==-1 which signifies "disabled"
int i = 0;
while (!(dev->irq_resource[i].flags & IORESOURCE_UNSET) && i < DEVICE_COUNT_IRQ) i++;
if (i < DEVICE_COUNT_IRQ) {
- dev->irq_resource[i].start = irq;
+ dev->irq_resource[i].start = (unsigned long) irq;
dev->irq_resource[i].flags = IORESOURCE_IRQ; // Also clears _UNSET flag
}
}

-static void inline pnpbios_add_dmaresource(struct pci_dev *dev, int dma)
+static void pnpbios_add_dmaresource(struct pci_dev *dev, int dma)
{
- // Permit dma==-1 which signifies "disabled"
int i = 0;
while (!(dev->dma_resource[i].flags & IORESOURCE_UNSET) && i < DEVICE_COUNT_DMA) i++;
if (i < DEVICE_COUNT_DMA) {
- dev->dma_resource[i].start = dma;
+ dev->dma_resource[i].start = (unsigned long) dma;
dev->dma_resource[i].flags = IORESOURCE_DMA; // Also clears _UNSET flag
}
}

-static void inline pnpbios_add_ioresource(struct pci_dev *dev, int io, int len)
+static void 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++;
if (i < DEVICE_COUNT_RESOURCE) {
- dev->resource[i].start = io;
- dev->resource[i].end = io + len;
+ dev->resource[i].start = (unsigned long) io;
+ dev->resource[i].end = (unsigned long)(io + len - 1);
dev->resource[i].flags = IORESOURCE_IO; // Also clears _UNSET flag
}
}

-static void inline pnpbios_add_memresource(struct pci_dev *dev, int mem, int len)
+static void 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 = mem;
- dev->resource[i].end = mem + len;
+ dev->resource[i].start = (unsigned long) mem;
+ dev->resource[i].end = (unsigned long)(mem + len - 1);
dev->resource[i].flags = IORESOURCE_MEM; // Also clears _UNSET flag
}
}

-/*
- * request I/O ports which are used according to the PnP BIOS
- * to avoid I/O conflicts.
- */
-static void mboard_request(char *pnpid, int io, int len)
-{
- struct resource *res;
- char *regionid;
-
- if (
- 0 != strcmp(pnpid,"PNP0c01") && /* memory controller */
- 0 != strcmp(pnpid,"PNP0c02") /* system peripheral: other */
- ) {
- return;
- }
-
- if (io < 0x100) {
- /*
- * Below 0x100 is only standard PC hardware
- * (pics, kbd, timer, dma, ...)
- *
- * We should not get resource conflicts there,
- * and the kernel reserves these anyway
- * (see arch/i386/kernel/setup.c).
- */
- return;
- }
-
- /*
- * 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
- * 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.
- */
- regionid = pnp_bios_kmalloc(16, GFP_KERNEL);
- if ( regionid == NULL )
- return;
- sprintf(regionid, "PnPBIOS %s", pnpid);
- 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;
-}
-
-
-#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)
+static void pnpbios_node_resource_data_to_dev(struct pnp_bios_node *node, struct pci_dev *dev)
{
unsigned char *p = node->data, *lastp=NULL;
int i;

/*
- * First, set dev contents to default values
+ * First, set resource info to default values
*/
- memset(dev,0,sizeof(struct pci_dev));
for (i=0;i<DEVICE_COUNT_RESOURCE;i++) {
- /* dev->resource[i].start = 0; */
+ dev->resource[i].start = 0; // "disabled"
dev->resource[i].flags = IORESOURCE_UNSET;
}
for (i=0;i<DEVICE_COUNT_IRQ;i++) {
@@ -751,7 +701,7 @@
}

/*
- * Fill in dev info
+ * Fill in dev resource info
*/
while ( (char *)p < ((char *)node->data + node->size )) {
if(p==lastp) break;
@@ -795,7 +745,7 @@
switch (p[0]>>3) {
case 0x04: // irq
{
- int i, mask, irq = -1; // "disabled"
+ int i, mask, irq = -1;
mask= p[1] + p[2]*256;
for (i=0;i<16;i++, mask=mask>>1)
if(mask & 0x01) irq=i;
@@ -804,7 +754,7 @@
}
case 0x05: // dma
{
- int i, mask, dma = -1; // "disabled"
+ int i, mask, dma = -1;
mask = p[1];
for (i=0;i<8;i++, mask = mask>>1)
if(mask & 0x01) dma=i;
@@ -816,7 +766,6 @@
int io= p[2] + p[3] *256;
int len = p[7];
pnpbios_add_ioresource(dev, io, len);
- mboard_request(pnpid32_to_pnpid(node->eisa_id),io,len);
break;
}
case 0x09: // fixed location io
@@ -843,42 +792,53 @@

static LIST_HEAD(pnpbios_devices);

-int pnp_bios_present(void)
-{
- return (pnp_bios_inst_struc != NULL);
-}
-
-EXPORT_SYMBOL(pnp_bios_present);
-
-static int __init pnpbios_insert_device(struct pci_dev *dev)
+static int inline pnpbios_insert_device(struct pci_dev *dev)
{
/* FIXME: Need to check for re-add of existing node */
list_add_tail(&dev->global_list, &pnpbios_devices);
return 0;
}

-/*
- * Build the list of pci_dev objects from the PnP table
- */
-
+#define HEX(id,a) hex[((id)>>a) & 15]
+#define CHAR(id,a) (0x40 + (((id)>>a) & 31))
+//
+static void inline pnpid32_to_pnpid(u32 id, char *str)
+{
+ const char *hex = "0123456789abcdef";
+
+ 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;
+}
+//
+#undef CHAR
+#undef HEX
+
static void __init pnpbios_build_devlist(void)
{
int i;
int nodenum;
int nodes_got = 0;
+ int devs = 0;
struct pnp_bios_node *node;
struct pnp_dev_node_info node_info;
struct pci_dev *dev;
- char *pnpid;
-

- if (!pnp_bios_present ())
+ if (!pnp_bios_is_present ())
return;

if (pnp_bios_dev_node_info(&node_info) != 0)
return;

- node = pnp_bios_kmalloc(node_info.max_node_size, GFP_KERNEL);
+ node = pnpbios_kmalloc(node_info.max_node_size, GFP_KERNEL);
if (!node)
return;

@@ -891,22 +851,45 @@
if (pnp_bios_get_dev_node((u8 *)&nodenum, (char )1 , node))
break;
nodes_got++;
- dev = pnp_bios_kmalloc(sizeof (struct pci_dev), GFP_KERNEL);
+ dev = pnpbios_kmalloc(sizeof (struct pci_dev), GFP_KERNEL);
if (!dev)
break;
- pnpbios_rawdata_2_pci_dev(node,dev);
+ memset(dev,0,sizeof(struct pci_dev));
dev->devfn=thisnodenum;
- pnpid = pnpid32_to_pnpid(node->eisa_id);
memcpy(dev->name,"PNPBIOS",8);
- memcpy(dev->slot_name,pnpid,8);
+ pnpid32_to_pnpid(node->eisa_id,dev->slot_name);
+ pnpbios_node_resource_data_to_dev(node,dev);
if(pnpbios_insert_device(dev)<0)
kfree(dev);
+ devs++;
}
kfree(node);

- printk(KERN_INFO "PnPBIOS: %i node%s reported by PnP BIOS\n", nodes_got, nodes_got != 1 ? "s" : "");
+ printk(KERN_INFO "PnPBIOS: %i node%s reported by PnP BIOS; %i recorded by driver.\n",
+ nodes_got, nodes_got != 1 ? "s" : "", devs);
}

+static struct pci_dev *pnpbios_find_device_by_nodenum( u8 nodenum )
+{
+ struct pci_dev *dev;
+
+ pnpbios_for_each_dev(dev) {
+ if(dev->devfn == nodenum)
+ return dev;
+ }
+
+ return NULL;
+}
+
+static void pnpbios_update_devlist( u8 nodenum, struct pnp_bios_node *data )
+{
+ struct pci_dev *dev = pnpbios_find_device_by_nodenum( nodenum );
+ if ( dev ) {
+ pnpbios_node_resource_data_to_dev(data,dev);
+ }
+
+ return;
+}

/*
*
@@ -920,22 +903,19 @@
struct pci_dev *pnpbios_find_device(char *pnpid, struct pci_dev *prev)
{
struct pci_dev *dev;
- int num;
-
- if(prev==NULL)
- num=0; /* Start from beginning */
- else
- num=prev->devfn + 1; /* Encode node number here */
+ int nodenum;

+ nodenum = 0;
+ if(prev)
+ nodenum=prev->devfn + 1; /* Encode node number here */

- pnpbios_for_each_dev(dev)
- {
- if(dev->devfn >= num)
- {
+ pnpbios_for_each_dev(dev) {
+ if(dev->devfn >= nodenum) {
if(memcmp(dev->slot_name, pnpid, 7)==0)
return dev;
}
}
+
return NULL;
}

@@ -1049,54 +1029,145 @@

EXPORT_SYMBOL(pnpbios_unregister_driver);

+/*
+ *
+ * RESOURCE RESERVATION FUNCTIONS
+ *
+ */
+
+static void __init pnpbios_reserve_resource_range(char *pnpid, int start, int end)
+{
+ struct resource *res;
+ char *regionid;
+
+ regionid = pnpbios_kmalloc(16, GFP_KERNEL);
+ if ( regionid == NULL )
+ return;
+ sprintf(regionid, "PnPBIOS %s", pnpid);
+ res = request_region(start,end-start+1,regionid);
+ if ( res == NULL )
+ kfree( regionid );
+ /*
+ * Failures at this point are usually harmless. pci quirks for
+ * example do reserve stuff they know about too, so we may well
+ * have double reservations.
+ */
+ printk(
+ "PnPBIOS: %s: 0x%x-0x%x %s reserved\n",
+ pnpid, start, end,
+ NULL != res ? "has been" : "was already"
+ );
+
+ return;
+}
+
+static void __init pnpbios_reserve_resources_of_dev( struct pci_dev *dev )
+{
+ int i;
+
+ for (i=0;i<DEVICE_COUNT_RESOURCE;i++) {
+ if ( dev->resource[i].flags & IORESOURCE_UNSET )
+ /* resource record not used */
+ break;
+ if ( dev->resource[i].start == 0 )
+ /* resource disabled */
+ continue;
+ if ( dev->resource[i].start < 0x100 )
+ /*
+ * Below 0x100 is only standard PC hardware
+ * (pics, kbd, timer, dma, ...)
+ *
+ * We should not get resource conflicts there,
+ * and the kernel reserves these anyway
+ * (see arch/i386/kernel/setup.c).
+ */
+ continue;
+ if ( dev->resource[i].end < dev->resource[i].start )
+ /* insane */
+ continue;
+ pnpbios_reserve_resource_range(
+ dev->slot_name,
+ dev->resource[i].start,
+ dev->resource[i].end
+ );
+ }
+
+ return;
+}
+
+/*
+ * Reserve resources used by system board devices
+ *
+ * We really shouldn't just _reserve_ these regions since
+ * that prevents the device drivers from claiming them.
+ */
+static void __init pnpbios_reserve_resources( void )
+{
+ struct pci_dev *dev;
+
+ pnpbios_for_each_dev(dev) {
+ if (
+ 0 != strcmp(dev->slot_name,"PNP0c01") && /* memory controller */
+ 0 != strcmp(dev->slot_name,"PNP0c02") /* system peripheral: other */
+ ) {
+ continue;
+ }
+ pnpbios_reserve_resources_of_dev(dev);
+ }
+
+ return;
+}
+
/*
*
* INIT AND EXIT
*
*
- * Search the defined area (0xf0000-0xffff0) for a valid PnP BIOS
- * structure and, if one is found, sets up the selectors and
- * entry points
*/

extern int is_sony_vaio_laptop;

-static int pnp_bios_disabled;
-static int pnp_bios_dont_use_current_config;
+static int pnpbios_disabled;
+int pnpbios_dont_use_current_config;

-static int disable_pnp_bios(char *str)
+static int __init pnpbios_disable_pnp_bios(char *str)
{
- pnp_bios_disabled=1;
+ pnpbios_disabled=1;
return 0;
}

-static int disable_use_of_current_config(char *str)
+static int __init pnpbios_disable_use_of_current_config(char *str)
{
- pnp_bios_dont_use_current_config=1;
+ pnpbios_dont_use_current_config=1;
return 0;
}

-__setup("nobiospnp", disable_pnp_bios);
-__setup("nobioscurrpnp", disable_use_of_current_config);
+__setup("nobiospnp", pnpbios_disable_pnp_bios);
+__setup("nobioscurrpnp", pnpbios_disable_use_of_current_config);

-void pnp_bios_init(void)
+void __init pnpbios_init(void)
{
- union pnpbios *check;
+ union pnp_bios_expansion_header *check;
u8 sum;
int i, length;

spin_lock_init(&pnp_bios_lock);

- if(pnp_bios_disabled) {
+ if(pnpbios_disabled) {
printk(KERN_INFO "PnPBIOS: Disabled.\n");
return;
}

if ( is_sony_vaio_laptop )
- pnp_bios_dont_use_current_config = 1;
+ pnpbios_dont_use_current_config = 1;

- for (check = (union pnpbios *) __va(0xf0000);
- check < (union pnpbios *) __va(0xffff0);
+ /*
+ * Search the defined area (0xf0000-0xffff0) for a valid PnP BIOS
+ * structure and, if one is found, sets up the selectors and
+ * entry points
+ */
+ for (check = (union pnp_bios_expansion_header *) __va(0xf0000);
+ check < (union pnp_bios_expansion_header *) __va(0xffff0);
((void *) (check)) += 16) {
if (check->fields.signature != PNP_SIGNATURE)
continue;
@@ -1123,12 +1194,14 @@
Q_SET_SEL(PNP_DS, check->fields.pm16dseg, 64 * 1024);
pnp_bios_callpoint.offset = check->fields.pm16offset;
pnp_bios_callpoint.segment = PNP_CS16;
- pnp_bios_inst_struc = check;
+ pnp_bios_hdr = check;
break;
}
+
pnpbios_build_devlist();
+ pnpbios_reserve_resources();
#ifdef CONFIG_PROC_FS
- pnp_proc_init( pnp_bios_dont_use_current_config );
+ pnpbios_proc_init();
#endif
#ifdef CONFIG_HOTPLUG
init_completion(&unload_sem);
@@ -1142,16 +1215,18 @@
MODULE_LICENSE("GPL");

/* We have to run it early and specifically in non modular.. */
-module_init(pnp_bios_init);
+module_init(pnpbios_init);

#ifdef CONFIG_HOTPLUG
-static void pnp_bios_exit(void)
+static void pnpbios_exit(void)
{
+ /* free_resources() ought to go here */
+ /* pnpbios_proc_done() */
unloading = 1;
wait_for_completion(&unload_sem);
}

-module_exit(pnp_bios_exit);
+module_exit(pnpbios_exit);

#endif
#endif
--- linux-2.4.10-ac12/drivers/pnp/pnp_proc.c Wed Oct 10 22:09:19 2001
+++ linux-2.4.10-ac12-fix/drivers/pnp/pnp_proc.c Sat Oct 13 08:42:05 2001
@@ -31,10 +31,10 @@
*eof = 1;
return 0;
}
- node = kmalloc(node_info.max_node_size, GFP_KERNEL);
+ node = pnpbios_kmalloc(node_info.max_node_size, GFP_KERNEL);
if (!node) return -ENOMEM;
for (i=0,nodenum=0;i<0xff && nodenum!=0xff; i++) {
- if ( pnp_bios_get_dev_node(&nodenum, 1, node) )
+ if ( pnpbios_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,
@@ -57,9 +57,9 @@
*eof = 1;
return 0;
}
- node = kmalloc(node_info.max_node_size, GFP_KERNEL);
+ node = pnpbios_kmalloc(node_info.max_node_size, GFP_KERNEL);
if (!node) return -ENOMEM;
- if ( pnp_bios_get_dev_node(&nodenum, boot, node) )
+ if ( pnpbios_get_dev_node(&nodenum, boot, node) )
return -EIO;
len = node->size - sizeof(struct pnp_bios_node);
memcpy(buf, node->data, len);
@@ -74,22 +74,25 @@
int boot = (long)data >> 8;
u8 nodenum = (long)data;

- node = kmalloc(node_info.max_node_size, GFP_KERNEL);
+ node = pnpbios_kmalloc(node_info.max_node_size, GFP_KERNEL);
if (!node) return -ENOMEM;
- if ( pnp_bios_get_dev_node(&nodenum, boot, node) )
+ if ( pnpbios_get_dev_node(&nodenum, boot, node) )
return -EIO;
if (count != node->size - sizeof(struct pnp_bios_node))
return -EINVAL;
memcpy(node->data, buf, count);
- if (pnp_bios_set_dev_node(node->handle, boot, node) != 0)
+ if (pnpbios_set_dev_node(node->handle, boot, node) != 0)
return -EINVAL;
kfree(node);
return count;
}

-static int pnp_proc_dont_use_current_config;
-
-void pnp_proc_init( int dont_use_current )
+/*
+ * When this is called, pnpbios functions are assumed to
+ * work and the pnpbios_dont_use_current_config flag
+ * should already have been set to the appropriate value
+ */
+void pnpbios_proc_init( void )
{
struct pnp_bios_node *node;
struct proc_dir_entry *ent;
@@ -97,10 +100,7 @@
int i;
u8 nodenum;

- pnp_proc_dont_use_current_config = dont_use_current;
-
- if (!pnp_bios_present()) return;
- if (pnp_bios_dev_node_info(&node_info) != 0) return;
+ if (pnpbios_dev_node_info(&node_info) != 0) return;

proc_pnp = proc_mkdir("pnp", proc_bus);
if (!proc_pnp) return;
@@ -108,13 +108,13 @@
if (!proc_pnp_boot) return;
create_proc_read_entry("devices", 0, proc_pnp, proc_read_devices, NULL);

- node = kmalloc(node_info.max_node_size, GFP_KERNEL);
+ node = pnpbios_kmalloc(node_info.max_node_size, GFP_KERNEL);
if (!node) return;
for (i=0,nodenum = 0; i<0xff && nodenum != 0xff; i++) {
- if (pnp_bios_get_dev_node(&nodenum, 1, node) != 0)
+ if (pnpbios_get_dev_node(&nodenum, 1, node) != 0)
break;
sprintf(name, "%02x", node->handle);
- if ( !pnp_proc_dont_use_current_config ) {
+ if ( !pnpbios_dont_use_current_config ) {
ent = create_proc_entry(name, 0, proc_pnp);
if (ent) {
ent->read_proc = proc_read_node;
@@ -132,7 +132,7 @@
kfree(node);
}

-void pnp_proc_done(void)
+void pnpbios_proc_done(void)
{
int i;
char name[3];
@@ -141,7 +141,7 @@

for (i=0; i<0xff; i++) {
sprintf(name, "%02x", i);
- if ( !pnp_proc_dont_use_current_config )
+ if ( !pnpbios_dont_use_current_config )
remove_proc_entry(name, proc_pnp);
remove_proc_entry(name, proc_pnp_boot);
}

2001-10-16 03:29:52

by Thomas Hood

[permalink] [raw]
Subject: [PATCH] PnP BIOS patch against 2.4.12-ac2

Here's an updated patch, now against 2.4.12-ac2.

In addition to:
1) Fix bugs in resource reservation:
- end of reserved range off by +1
- didn't reserve _all_ system board resources
2) Change code so that set_dev_node updates the devlist, so
drivers loaded after a setpnp will get up-to-date resource
information. Because I haven't protected devlist update
code with locks, this feature isn't SMP safe yet.
3) Miscellaneous code cleanups. Use "pnpbios" more consistently.
Improve printk output. Etc.
plus (I forget to mention):
4) Don't EXPORT_SYMBOL lowlevel PnP BIOS access functions since
they aren't used by anything except the proc routines which
don't need them to be EXPORT_SYMBOL to link to them.

this patch adds:
5) Declare announce_device in header (since it is EXPORT_SYMBOL
in pnp_bios.c, presumably for a reason).

--
Thomas

The patch:
--- linux-2.4.12-ac2/init/main.c Sun Oct 14 15:39:55 2001
+++ linux-2.4.12-ac2-fix/init/main.c Sun Oct 14 15:59:44 2001
@@ -822,7 +822,7 @@
isapnp_init();
#endif
#ifdef CONFIG_PNPBIOS
- pnp_bios_init();
+ pnpbios_init();
#endif

#ifdef CONFIG_TC
--- linux-2.4.12-ac2/include/linux/pnp_bios.h Wed Oct 10 22:09:57 2001
+++ linux-2.4.12-ac2-fix/include/linux/pnp_bios.h Mon Oct 15 23:04:21 2001
@@ -132,30 +132,37 @@
return (struct pnpbios_driver *)dev->driver;
}

-extern void pnp_bios_init (void);
-extern int pnp_bios_dev_node_info (struct pnp_dev_node_info *data);
-extern int pnp_bios_get_dev_node (u8 *nodenum, char config, struct pnp_bios_node *data);
-extern int pnp_bios_set_dev_node (u8 nodenum, char config, struct pnp_bios_node *data);
-extern int pnp_bios_get_event (u16 *message);
-extern int pnp_bios_send_message (u16 message);
-extern int pnp_bios_set_stat_res (char *info);
-extern int pnp_bios_get_stat_res (char *info);
-extern int pnp_bios_apm_id_table (char *table, u16 *size);
-extern int pnp_bios_isapnp_config (struct pnp_isa_config_struc *data);
-extern int pnp_bios_escd_info (struct escd_info_struc *data);
-extern int pnp_bios_read_escd (char *data, u32 nvram_base);
-extern int pnp_bios_write_escd (char *data, u32 nvram_base);
-
-extern void pnp_proc_init ( int dont_use_current );
-
#ifdef CONFIG_PNPBIOS
#define pnpbios_for_each_dev(dev) \
for(dev = pnpbios_dev_g(pnpbios_devices.next); dev != pnpbios_dev_g(&pnpbios_devices); dev = pnpbios_dev_g(dev->global_list.next))
-extern int pnp_bios_present (void);
+
+/* exported functions */
extern struct pci_dev *pnpbios_find_device(char *pnpid, struct pci_dev *dev);
-extern int pnpbios_register_driver(struct pnpbios_driver *drv);
+extern int pnpbios_announce_device(struct pnpbios_driver *drv, struct pci_dev *dev);
+extern int pnpbios_register_driver(struct pnpbios_driver *drv);
extern void pnpbios_unregister_driver(struct pnpbios_driver *drv);

+/* non-exported functions */
+extern int pnpbios_dont_use_current_config;
+extern void *pnpbios_kmalloc(size_t size, int f);
+extern void pnpbios_init (void);
+extern void pnpbios_proc_init (void);
+
+extern int pnpbios_dev_node_info (struct pnp_dev_node_info *data);
+extern int pnpbios_get_dev_node (u8 *nodenum, char config, struct pnp_bios_node *data);
+extern int pnpbios_set_dev_node (u8 nodenum, char config, struct pnp_bios_node *data);
+#if needed
+extern int pnpbios_get_event (u16 *message);
+extern int pnpbios_send_message (u16 message);
+extern int pnpbios_set_stat_res (char *info);
+extern int pnpbios_get_stat_res (char *info);
+extern int pnpbios_apm_id_table (char *table, u16 *size);
+extern int pnpbios_isapnp_config (struct pnp_isa_config_struc *data);
+extern int pnpbios_escd_info (struct escd_info_struc *data);
+extern int pnpbios_read_escd (char *data, u32 nvram_base);
+extern int pnpbios_write_escd (char *data, u32 nvram_base);
+#endif
+
/*
* a helper function which helps ensure correct pnpbios_driver
* setup and cleanup for commonly-encountered hotplug/modular cases
@@ -189,22 +196,17 @@
return rc;
}

-#else
+#else /* CONFIG_PNPBIOS */
#define pnpbios_for_each_dev(dev) for(dev = NULL; 0; )

-static __inline__ int pnp_bios_present (void)
-{
- return 0;
-}
-
static __inline__ struct pci_dev *pnpbios_find_device(char *pnpid, struct pci_dev *dev)
{
return NULL;
}

-static __inline__ int pnpbios_module_init(struct pnpbios_driver *drv)
+static __inline__ int pnpbios_announce_device(struct pnpbios_driver *drv, struct pci_dev *dev)
{
- return -ENODEV;
+ return 0;
}

static __inline__ int pnpbios_register_driver(struct pnpbios_driver *drv)
@@ -217,7 +219,12 @@
return;
}

-#endif
+static __inline__ int pnpbios_module_init(struct pnpbios_driver *drv)
+{
+ return -ENODEV;
+}
+
+#endif /* CONFIG_PNPBIOS */
#endif /* __KERNEL__ */

#endif /* _LINUX_PNP_BIOS_H */
--- linux-2.4.12-ac2/drivers/pnp/pnp_bios.c Wed Oct 10 22:09:19 2001
+++ linux-2.4.12-ac2-fix/drivers/pnp/pnp_bios.c Mon Oct 15 23:13:34 2001
@@ -50,11 +50,17 @@
#define PNP_SIGNATURE (('$' << 0) + ('P' << 8) + ('n' << 16) + ('P' << 24))

/*
+ * Forward declarations
+ */
+
+static void pnpbios_update_devlist( u8 nodenum, struct pnp_bios_node *data );
+
+/*
* This is the standard structure used to identify the entry point
* to the Plug and Play bios
*/
#pragma pack(1)
-union pnpbios {
+union pnp_bios_expansion_header {
struct {
u32 signature; /* "$PnP" */
u8 version; /* in BCD */
@@ -83,7 +89,7 @@
u16 segment;
} pnp_bios_callpoint;

-static union pnpbios * pnp_bios_inst_struc = NULL;
+static union pnp_bios_expansion_header * pnp_bios_hdr = NULL;

/* The PnP entries in the GDT */
#define PNP_GDT 0x0060
@@ -214,12 +220,16 @@
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)
+/*
+ *
+ * UTILITY FUNCTIONS
+ *
+ */
+
+void *pnpbios_kmalloc(size_t size, int f)
{
void *p = kmalloc( size, f );
if ( p == NULL )
@@ -228,18 +238,29 @@
}

/*
+ * Call this only after init time
+ */
+static int pnp_bios_is_present(void)
+{
+ return (pnp_bios_hdr != NULL);
+}
+
+/*
*
* PnP BIOS ACCESS FUNCTIONS
*
+ * pnp_bios_* are local functions used to call the BIOS
+ * pnpbios_* are the public interface to these functions
+ *
*/

/*
* Call PnP BIOS with function 0x00, "get number of system device nodes"
*/
-static int pnp_bios_dev_node_info_silently(struct pnp_dev_node_info *data)
+static int pnp_bios_dev_node_info(struct pnp_dev_node_info *data)
{
u16 status;
- if (!pnp_bios_present ())
+ if (!pnp_bios_is_present ())
return PNP_FUNCTION_NOT_SUPPORTED;
Q2_SET_SEL(PNP_TS1, data, sizeof(struct pnp_dev_node_info));
status = call_pnp_bios(PNP_GET_NUM_SYS_DEV_NODES, 0, PNP_TS1, 2, PNP_TS1, PNP_DS, 0, 0);
@@ -247,11 +268,11 @@
return status;
}

-int pnp_bios_dev_node_info(struct pnp_dev_node_info *data)
+int pnpbios_dev_node_info(struct pnp_dev_node_info *data)
{
- u16 status = pnp_bios_dev_node_info_silently( data );
+ int status = pnp_bios_dev_node_info( data );
if ( status )
- printk(KERN_WARNING "PnPBIOS: PnP BIOS dev_node_info function returned error status 0x%x\n", status);
+ printk(KERN_WARNING "PnPBIOS: dev_node_info: Unexpected status 0x%x\n", status);
return status;
}

@@ -269,22 +290,25 @@
* or volatile current (0) config
* Output: *nodenum=next node or 0xff if no more nodes
*/
-static int pnp_bios_get_dev_node_silently(u8 *nodenum, char boot, struct pnp_bios_node *data)
+static int pnp_bios_get_dev_node(u8 *nodenum, char boot, struct pnp_bios_node *data)
{
u16 status;
- if (!pnp_bios_present ())
- return PNP_FUNCTION_NOT_SUPPORTED;
Q2_SET_SEL(PNP_TS1, nodenum, sizeof(char));
Q2_SET_SEL(PNP_TS2, data, 64 * 1024);
status = call_pnp_bios(PNP_GET_SYS_DEV_NODE, 0, PNP_TS1, 0, PNP_TS2, boot ? 2 : 1, PNP_DS, 0);
return status;
}

-int pnp_bios_get_dev_node(u8 *nodenum, char boot, struct pnp_bios_node *data)
+int pnpbios_get_dev_node(u8 *nodenum, char boot, struct pnp_bios_node *data)
{
- u16 status = pnp_bios_get_dev_node_silently( nodenum, boot, data );
+ int status;
+ if (!pnp_bios_is_present ())
+ return PNP_FUNCTION_NOT_SUPPORTED;
+ if ( !boot & pnpbios_dont_use_current_config )
+ return PNP_FUNCTION_NOT_SUPPORTED;
+ status = pnp_bios_get_dev_node( nodenum, boot, data );
if ( status )
- printk(KERN_WARNING "PnPBIOS: PnP BIOS get_dev_node function returned error status 0x%x\n", status);
+ printk(KERN_WARNING "PnPBIOS: get_dev_node: Unexpected 0x%x\n", status);
return status;
}

@@ -294,21 +318,35 @@
* boot = whether to set nonvolatile boot (!=0)
* or volatile current (0) config
*/
-static int pnp_bios_set_dev_node_silently(u8 nodenum, char boot, struct pnp_bios_node *data)
+static int pnp_bios_set_dev_node(u8 nodenum, char boot, struct pnp_bios_node *data)
{
u16 status;
- if (!pnp_bios_present ())
- return PNP_FUNCTION_NOT_SUPPORTED;
Q2_SET_SEL(PNP_TS1, data, /* *((u16 *) data)*/ 65536);
status = call_pnp_bios(PNP_SET_SYS_DEV_NODE, nodenum, 0, PNP_TS1, boot ? 2 : 1, PNP_DS, 0, 0);
return status;
}

-int pnp_bios_set_dev_node(u8 nodenum, char boot, struct pnp_bios_node *data)
+int pnpbios_set_dev_node(u8 nodenum, char boot, struct pnp_bios_node *data)
{
- u16 status = pnp_bios_set_dev_node_silently( nodenum, boot, data );
- if ( status )
- printk(KERN_WARNING "PnPBIOS: PnP BIOS set_dev_node function returned error status 0x%x\n", status);
+ int status;
+ if (!pnp_bios_is_present ())
+ return PNP_FUNCTION_NOT_SUPPORTED;
+ if ( !boot & pnpbios_dont_use_current_config )
+ return PNP_FUNCTION_NOT_SUPPORTED;
+ status = pnp_bios_set_dev_node( nodenum, boot, data );
+ if ( status ) {
+ printk(KERN_WARNING "PnPBIOS: set_dev_node: Unexpected set_dev_node status 0x%x\n", status);
+ return status;
+ }
+ if ( !boot ) { /* Update devlist */
+ u8 thisnodenum = nodenum;
+ status = pnp_bios_get_dev_node( &nodenum, boot, data );
+ if ( status ) {
+ printk(KERN_WARNING "PnPBIOS: set_dev_node: Unexpected get_dev_node status 0x%x\n", status);
+ return status;
+ }
+ pnpbios_update_devlist( thisnodenum, data );
+ }
return status;
}

@@ -319,7 +357,7 @@
static int pnp_bios_get_event(u16 *event)
{
u16 status;
- if (!pnp_bios_present ())
+ if (!pnp_bios_is_present ())
return PNP_FUNCTION_NOT_SUPPORTED;
Q2_SET_SEL(PNP_TS1, event, sizeof(u16));
status = call_pnp_bios(PNP_GET_EVENT, 0, PNP_TS1, PNP_DS, 0, 0 ,0 ,0);
@@ -334,7 +372,7 @@
static int pnp_bios_send_message(u16 message)
{
u16 status;
- if (!pnp_bios_present ())
+ if (!pnp_bios_is_present ())
return PNP_FUNCTION_NOT_SUPPORTED;
status = call_pnp_bios(PNP_SEND_MESSAGE, message, PNP_DS, 0, 0, 0, 0, 0);
return status;
@@ -348,7 +386,7 @@
static int pnp_bios_dock_station_info(struct pnp_docking_station_info *data)
{
u16 status;
- if (!pnp_bios_present ())
+ if (!pnp_bios_is_present ())
return PNP_FUNCTION_NOT_SUPPORTED;
Q2_SET_SEL(PNP_TS1, data, sizeof(struct pnp_docking_station_info));
status = call_pnp_bios(PNP_GET_DOCKING_STATION_INFORMATION, 0, PNP_TS1, PNP_DS, 0, 0, 0, 0);
@@ -364,7 +402,7 @@
static int pnp_bios_set_stat_res(char *info)
{
u16 status;
- if (!pnp_bios_present ())
+ if (!pnp_bios_is_present ())
return PNP_FUNCTION_NOT_SUPPORTED;
Q2_SET_SEL(PNP_TS1, info, *((u16 *) info));
status = call_pnp_bios(PNP_SET_STATIC_ALLOCED_RES_INFO, 0, PNP_TS1, PNP_DS, 0, 0, 0, 0);
@@ -380,7 +418,7 @@
static int pnp_bios_get_stat_res(char *info)
{
u16 status;
- if (!pnp_bios_present ())
+ if (!pnp_bios_is_present ())
return PNP_FUNCTION_NOT_SUPPORTED;
Q2_SET_SEL(PNP_TS1, info, 64 * 1024);
status = call_pnp_bios(PNP_GET_STATIC_ALLOCED_RES_INFO, 0, PNP_TS1, PNP_DS, 0, 0, 0, 0);
@@ -395,7 +433,7 @@
static int pnp_bios_apm_id_table(char *table, u16 *size)
{
u16 status;
- if (!pnp_bios_present ())
+ if (!pnp_bios_is_present ())
return PNP_FUNCTION_NOT_SUPPORTED;
Q2_SET_SEL(PNP_TS1, table, *size);
Q2_SET_SEL(PNP_TS2, size, sizeof(u16));
@@ -411,7 +449,7 @@
static int pnp_bios_isapnp_config(struct pnp_isa_config_struc *data)
{
u16 status;
- if (!pnp_bios_present ())
+ if (!pnp_bios_is_present ())
return PNP_FUNCTION_NOT_SUPPORTED;
Q2_SET_SEL(PNP_TS1, data, sizeof(struct pnp_isa_config_struc));
status = call_pnp_bios(PNP_GET_PNP_ISA_CONFIG_STRUC, 0, PNP_TS1, PNP_DS, 0, 0, 0, 0);
@@ -426,7 +464,7 @@
static int pnp_bios_escd_info(struct escd_info_struc *data)
{
u16 status;
- if (!pnp_bios_present ())
+ if (!pnp_bios_is_present ())
return ESCD_FUNCTION_NOT_SUPPORTED;
Q2_SET_SEL(PNP_TS1, data, sizeof(struct escd_info_struc));
status = call_pnp_bios(PNP_GET_ESCD_INFO, 0, PNP_TS1, 2, PNP_TS1, 4, PNP_TS1, PNP_DS);
@@ -442,7 +480,7 @@
static int pnp_bios_read_escd(char *data, u32 nvram_base)
{
u16 status;
- if (!pnp_bios_present ())
+ if (!pnp_bios_is_present ())
return ESCD_FUNCTION_NOT_SUPPORTED;
Q2_SET_SEL(PNP_TS1, data, 64 * 1024);
set_base(gdt[PNP_TS2 >> 3], nvram_base);
@@ -459,7 +497,7 @@
static int pnp_bios_write_escd(char *data, u32 nvram_base)
{
u16 status;
- if (!pnp_bios_present ())
+ if (!pnp_bios_is_present ())
return ESCD_FUNCTION_NOT_SUPPORTED;
Q2_SET_SEL(PNP_TS1, data, 64 * 1024);
set_base(gdt[PNP_TS2 >> 3], nvram_base);
@@ -469,10 +507,6 @@
}
#endif

-EXPORT_SYMBOL(pnp_bios_dev_node_info);
-EXPORT_SYMBOL(pnp_bios_get_dev_node);
-EXPORT_SYMBOL(pnp_bios_set_dev_node);
-
/*
*
* PnP DOCKING FUNCTIONS
@@ -482,7 +516,6 @@
#ifdef CONFIG_HOTPLUG

static int unloading = 0;
-
static struct completion unload_sem;

/*
@@ -499,10 +532,10 @@
if (!current->fs->root) {
return -EAGAIN;
}
- if (!(envp = (char **) pnp_bios_kmalloc (20 * sizeof (char *), GFP_KERNEL))) {
+ if (!(envp = (char **) pnpbios_kmalloc (20 * sizeof (char *), GFP_KERNEL))) {
return -ENOMEM;
}
- if (!(buf = pnp_bios_kmalloc (256, GFP_KERNEL))) {
+ if (!(buf = pnpbios_kmalloc (256, GFP_KERNEL))) {
kfree (envp);
return -ENOMEM;
}
@@ -579,7 +612,7 @@
d = 1;
break;
default:
- printk(KERN_WARNING "PnPBIOS: Unexpected error 0x%x returned by BIOS.\n", err);
+ printk(KERN_WARNING "PnPBIOS: pnp_dock_thread: Unexpected status 0x%x returned by BIOS.\n", err);
continue;
}
if(d != docked)
@@ -587,7 +620,9 @@
if(pnp_dock_event(d, &now)==0)
{
docked = d;
-// printk(KERN_INFO "PnPBIOS: Docking station %stached.\n", docked?"at":"de");
+#if 0
+ printk(KERN_INFO "PnPBIOS: Docking station %stached.\n", docked?"at":"de");
+#endif
}
}
}
@@ -598,147 +633,62 @@

/*
*
- * NODE DATA HANDLING FUNCTIONS
+ * NODE DATA PARSING FUNCTIONS
*
*/

-static void inline pnpbios_add_irqresource(struct pci_dev *dev, int irq)
+static void pnpbios_add_irqresource(struct pci_dev *dev, int irq)
{
- // Permit irq==-1 which signifies "disabled"
int i = 0;
while (!(dev->irq_resource[i].flags & IORESOURCE_UNSET) && i < DEVICE_COUNT_IRQ) i++;
if (i < DEVICE_COUNT_IRQ) {
- dev->irq_resource[i].start = irq;
+ dev->irq_resource[i].start = (unsigned long) irq;
dev->irq_resource[i].flags = IORESOURCE_IRQ; // Also clears _UNSET flag
}
}

-static void inline pnpbios_add_dmaresource(struct pci_dev *dev, int dma)
+static void pnpbios_add_dmaresource(struct pci_dev *dev, int dma)
{
- // Permit dma==-1 which signifies "disabled"
int i = 0;
while (!(dev->dma_resource[i].flags & IORESOURCE_UNSET) && i < DEVICE_COUNT_DMA) i++;
if (i < DEVICE_COUNT_DMA) {
- dev->dma_resource[i].start = dma;
+ dev->dma_resource[i].start = (unsigned long) dma;
dev->dma_resource[i].flags = IORESOURCE_DMA; // Also clears _UNSET flag
}
}

-static void inline pnpbios_add_ioresource(struct pci_dev *dev, int io, int len)
+static void 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++;
if (i < DEVICE_COUNT_RESOURCE) {
- dev->resource[i].start = io;
- dev->resource[i].end = io + len;
+ dev->resource[i].start = (unsigned long) io;
+ dev->resource[i].end = (unsigned long)(io + len - 1);
dev->resource[i].flags = IORESOURCE_IO; // Also clears _UNSET flag
}
}

-static void inline pnpbios_add_memresource(struct pci_dev *dev, int mem, int len)
+static void 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 = mem;
- dev->resource[i].end = mem + len;
+ dev->resource[i].start = (unsigned long) mem;
+ dev->resource[i].end = (unsigned long)(mem + len - 1);
dev->resource[i].flags = IORESOURCE_MEM; // Also clears _UNSET flag
}
}

-/*
- * request I/O ports which are used according to the PnP BIOS
- * to avoid I/O conflicts.
- */
-static void mboard_request(char *pnpid, int io, int len)
-{
- struct resource *res;
- char *regionid;
-
- if (
- 0 != strcmp(pnpid,"PNP0c01") && /* memory controller */
- 0 != strcmp(pnpid,"PNP0c02") /* system peripheral: other */
- ) {
- return;
- }
-
- if (io < 0x100) {
- /*
- * Below 0x100 is only standard PC hardware
- * (pics, kbd, timer, dma, ...)
- *
- * We should not get resource conflicts there,
- * and the kernel reserves these anyway
- * (see arch/i386/kernel/setup.c).
- */
- return;
- }
-
- /*
- * 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
- * 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.
- */
- regionid = pnp_bios_kmalloc(16, GFP_KERNEL);
- if ( regionid == NULL )
- return;
- sprintf(regionid, "PnPBIOS %s", pnpid);
- 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;
-}
-
-
-#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)
+static void pnpbios_node_resource_data_to_dev(struct pnp_bios_node *node, struct pci_dev *dev)
{
unsigned char *p = node->data, *lastp=NULL;
int i;

/*
- * First, set dev contents to default values
+ * First, set resource info to default values
*/
- memset(dev,0,sizeof(struct pci_dev));
for (i=0;i<DEVICE_COUNT_RESOURCE;i++) {
- /* dev->resource[i].start = 0; */
+ dev->resource[i].start = 0; // "disabled"
dev->resource[i].flags = IORESOURCE_UNSET;
}
for (i=0;i<DEVICE_COUNT_IRQ;i++) {
@@ -751,7 +701,7 @@
}

/*
- * Fill in dev info
+ * Fill in dev resource info
*/
while ( (char *)p < ((char *)node->data + node->size )) {
if(p==lastp) break;
@@ -795,7 +745,7 @@
switch (p[0]>>3) {
case 0x04: // irq
{
- int i, mask, irq = -1; // "disabled"
+ int i, mask, irq = -1;
mask= p[1] + p[2]*256;
for (i=0;i<16;i++, mask=mask>>1)
if(mask & 0x01) irq=i;
@@ -804,7 +754,7 @@
}
case 0x05: // dma
{
- int i, mask, dma = -1; // "disabled"
+ int i, mask, dma = -1;
mask = p[1];
for (i=0;i<8;i++, mask = mask>>1)
if(mask & 0x01) dma=i;
@@ -816,7 +766,6 @@
int io= p[2] + p[3] *256;
int len = p[7];
pnpbios_add_ioresource(dev, io, len);
- mboard_request(pnpid32_to_pnpid(node->eisa_id),io,len);
break;
}
case 0x09: // fixed location io
@@ -843,42 +792,53 @@

static LIST_HEAD(pnpbios_devices);

-int pnp_bios_present(void)
-{
- return (pnp_bios_inst_struc != NULL);
-}
-
-EXPORT_SYMBOL(pnp_bios_present);
-
-static int __init pnpbios_insert_device(struct pci_dev *dev)
+static int inline pnpbios_insert_device(struct pci_dev *dev)
{
/* FIXME: Need to check for re-add of existing node */
list_add_tail(&dev->global_list, &pnpbios_devices);
return 0;
}

-/*
- * Build the list of pci_dev objects from the PnP table
- */
-
+#define HEX(id,a) hex[((id)>>a) & 15]
+#define CHAR(id,a) (0x40 + (((id)>>a) & 31))
+//
+static void inline pnpid32_to_pnpid(u32 id, char *str)
+{
+ const char *hex = "0123456789abcdef";
+
+ 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;
+}
+//
+#undef CHAR
+#undef HEX
+
static void __init pnpbios_build_devlist(void)
{
int i;
int nodenum;
int nodes_got = 0;
+ int devs = 0;
struct pnp_bios_node *node;
struct pnp_dev_node_info node_info;
struct pci_dev *dev;
- char *pnpid;
-

- if (!pnp_bios_present ())
+ if (!pnp_bios_is_present ())
return;

if (pnp_bios_dev_node_info(&node_info) != 0)
return;

- node = pnp_bios_kmalloc(node_info.max_node_size, GFP_KERNEL);
+ node = pnpbios_kmalloc(node_info.max_node_size, GFP_KERNEL);
if (!node)
return;

@@ -891,22 +851,45 @@
if (pnp_bios_get_dev_node((u8 *)&nodenum, (char )1 , node))
break;
nodes_got++;
- dev = pnp_bios_kmalloc(sizeof (struct pci_dev), GFP_KERNEL);
+ dev = pnpbios_kmalloc(sizeof (struct pci_dev), GFP_KERNEL);
if (!dev)
break;
- pnpbios_rawdata_2_pci_dev(node,dev);
+ memset(dev,0,sizeof(struct pci_dev));
dev->devfn=thisnodenum;
- pnpid = pnpid32_to_pnpid(node->eisa_id);
memcpy(dev->name,"PNPBIOS",8);
- memcpy(dev->slot_name,pnpid,8);
+ pnpid32_to_pnpid(node->eisa_id,dev->slot_name);
+ pnpbios_node_resource_data_to_dev(node,dev);
if(pnpbios_insert_device(dev)<0)
kfree(dev);
+ devs++;
}
kfree(node);

- printk(KERN_INFO "PnPBIOS: %i node%s reported by PnP BIOS\n", nodes_got, nodes_got != 1 ? "s" : "");
+ printk(KERN_INFO "PnPBIOS: %i node%s reported by PnP BIOS; %i recorded by driver.\n",
+ nodes_got, nodes_got != 1 ? "s" : "", devs);
}

+static struct pci_dev *pnpbios_find_device_by_nodenum( u8 nodenum )
+{
+ struct pci_dev *dev;
+
+ pnpbios_for_each_dev(dev) {
+ if(dev->devfn == nodenum)
+ return dev;
+ }
+
+ return NULL;
+}
+
+static void pnpbios_update_devlist( u8 nodenum, struct pnp_bios_node *data )
+{
+ struct pci_dev *dev = pnpbios_find_device_by_nodenum( nodenum );
+ if ( dev ) {
+ pnpbios_node_resource_data_to_dev(data,dev);
+ }
+
+ return;
+}

/*
*
@@ -920,22 +903,19 @@
struct pci_dev *pnpbios_find_device(char *pnpid, struct pci_dev *prev)
{
struct pci_dev *dev;
- int num;
-
- if(prev==NULL)
- num=0; /* Start from beginning */
- else
- num=prev->devfn + 1; /* Encode node number here */
+ int nodenum;

+ nodenum = 0;
+ if(prev)
+ nodenum=prev->devfn + 1; /* Encode node number here */

- pnpbios_for_each_dev(dev)
- {
- if(dev->devfn >= num)
- {
+ pnpbios_for_each_dev(dev) {
+ if(dev->devfn >= nodenum) {
if(memcmp(dev->slot_name, pnpid, 7)==0)
return dev;
}
}
+
return NULL;
}

@@ -969,8 +949,7 @@
return NULL;
}

-static int
-pnpbios_announce_device(struct pnpbios_driver *drv, struct pci_dev *dev)
+int pnpbios_announce_device(struct pnpbios_driver *drv, struct pci_dev *dev)
{
const struct pnpbios_device_id *id;
int ret = 0;
@@ -1049,54 +1028,145 @@

EXPORT_SYMBOL(pnpbios_unregister_driver);

+/*
+ *
+ * RESOURCE RESERVATION FUNCTIONS
+ *
+ */
+
+static void __init pnpbios_reserve_resource_range(char *pnpid, int start, int end)
+{
+ struct resource *res;
+ char *regionid;
+
+ regionid = pnpbios_kmalloc(16, GFP_KERNEL);
+ if ( regionid == NULL )
+ return;
+ sprintf(regionid, "PnPBIOS %s", pnpid);
+ res = request_region(start,end-start+1,regionid);
+ if ( res == NULL )
+ kfree( regionid );
+ /*
+ * Failures at this point are usually harmless. pci quirks for
+ * example do reserve stuff they know about too, so we may well
+ * have double reservations.
+ */
+ printk(
+ "PnPBIOS: %s: 0x%x-0x%x %s reserved\n",
+ pnpid, start, end,
+ NULL != res ? "has been" : "was already"
+ );
+
+ return;
+}
+
+static void __init pnpbios_reserve_resources_of_dev( struct pci_dev *dev )
+{
+ int i;
+
+ for (i=0;i<DEVICE_COUNT_RESOURCE;i++) {
+ if ( dev->resource[i].flags & IORESOURCE_UNSET )
+ /* resource record not used */
+ break;
+ if ( dev->resource[i].start == 0 )
+ /* resource disabled */
+ continue;
+ if ( dev->resource[i].start < 0x100 )
+ /*
+ * Below 0x100 is only standard PC hardware
+ * (pics, kbd, timer, dma, ...)
+ *
+ * We should not get resource conflicts there,
+ * and the kernel reserves these anyway
+ * (see arch/i386/kernel/setup.c).
+ */
+ continue;
+ if ( dev->resource[i].end < dev->resource[i].start )
+ /* insane */
+ continue;
+ pnpbios_reserve_resource_range(
+ dev->slot_name,
+ dev->resource[i].start,
+ dev->resource[i].end
+ );
+ }
+
+ return;
+}
+
+/*
+ * Reserve resources used by system board devices
+ *
+ * We really shouldn't just _reserve_ these regions since
+ * that prevents the device drivers from claiming them.
+ */
+static void __init pnpbios_reserve_resources( void )
+{
+ struct pci_dev *dev;
+
+ pnpbios_for_each_dev(dev) {
+ if (
+ 0 != strcmp(dev->slot_name,"PNP0c01") && /* memory controller */
+ 0 != strcmp(dev->slot_name,"PNP0c02") /* system peripheral: other */
+ ) {
+ continue;
+ }
+ pnpbios_reserve_resources_of_dev(dev);
+ }
+
+ return;
+}
+
/*
*
* INIT AND EXIT
*
*
- * Search the defined area (0xf0000-0xffff0) for a valid PnP BIOS
- * structure and, if one is found, sets up the selectors and
- * entry points
*/

extern int is_sony_vaio_laptop;

-static int pnp_bios_disabled;
-static int pnp_bios_dont_use_current_config;
+static int pnpbios_disabled;
+int pnpbios_dont_use_current_config;

-static int disable_pnp_bios(char *str)
+static int __init pnpbios_disable_pnp_bios(char *str)
{
- pnp_bios_disabled=1;
+ pnpbios_disabled=1;
return 0;
}

-static int disable_use_of_current_config(char *str)
+static int __init pnpbios_disable_use_of_current_config(char *str)
{
- pnp_bios_dont_use_current_config=1;
+ pnpbios_dont_use_current_config=1;
return 0;
}

-__setup("nobiospnp", disable_pnp_bios);
-__setup("nobioscurrpnp", disable_use_of_current_config);
+__setup("nobiospnp", pnpbios_disable_pnp_bios);
+__setup("nobioscurrpnp", pnpbios_disable_use_of_current_config);

-void pnp_bios_init(void)
+void __init pnpbios_init(void)
{
- union pnpbios *check;
+ union pnp_bios_expansion_header *check;
u8 sum;
int i, length;

spin_lock_init(&pnp_bios_lock);

- if(pnp_bios_disabled) {
+ if(pnpbios_disabled) {
printk(KERN_INFO "PnPBIOS: Disabled.\n");
return;
}

if ( is_sony_vaio_laptop )
- pnp_bios_dont_use_current_config = 1;
+ pnpbios_dont_use_current_config = 1;

- for (check = (union pnpbios *) __va(0xf0000);
- check < (union pnpbios *) __va(0xffff0);
+ /*
+ * Search the defined area (0xf0000-0xffff0) for a valid PnP BIOS
+ * structure and, if one is found, sets up the selectors and
+ * entry points
+ */
+ for (check = (union pnp_bios_expansion_header *) __va(0xf0000);
+ check < (union pnp_bios_expansion_header *) __va(0xffff0);
((void *) (check)) += 16) {
if (check->fields.signature != PNP_SIGNATURE)
continue;
@@ -1123,12 +1193,14 @@
Q_SET_SEL(PNP_DS, check->fields.pm16dseg, 64 * 1024);
pnp_bios_callpoint.offset = check->fields.pm16offset;
pnp_bios_callpoint.segment = PNP_CS16;
- pnp_bios_inst_struc = check;
+ pnp_bios_hdr = check;
break;
}
+
pnpbios_build_devlist();
+ pnpbios_reserve_resources();
#ifdef CONFIG_PROC_FS
- pnp_proc_init( pnp_bios_dont_use_current_config );
+ pnpbios_proc_init();
#endif
#ifdef CONFIG_HOTPLUG
init_completion(&unload_sem);
@@ -1142,16 +1214,18 @@
MODULE_LICENSE("GPL");

/* We have to run it early and specifically in non modular.. */
-module_init(pnp_bios_init);
+module_init(pnpbios_init);

#ifdef CONFIG_HOTPLUG
-static void pnp_bios_exit(void)
+static void pnpbios_exit(void)
{
+ /* free_resources() ought to go here */
+ /* pnpbios_proc_done() */
unloading = 1;
wait_for_completion(&unload_sem);
}

-module_exit(pnp_bios_exit);
+module_exit(pnpbios_exit);

#endif
#endif
--- linux-2.4.12-ac2/drivers/pnp/pnp_proc.c Wed Oct 10 22:09:19 2001
+++ linux-2.4.12-ac2-fix/drivers/pnp/pnp_proc.c Sun Oct 14 15:59:44 2001
@@ -31,10 +31,10 @@
*eof = 1;
return 0;
}
- node = kmalloc(node_info.max_node_size, GFP_KERNEL);
+ node = pnpbios_kmalloc(node_info.max_node_size, GFP_KERNEL);
if (!node) return -ENOMEM;
for (i=0,nodenum=0;i<0xff && nodenum!=0xff; i++) {
- if ( pnp_bios_get_dev_node(&nodenum, 1, node) )
+ if ( pnpbios_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,
@@ -57,9 +57,9 @@
*eof = 1;
return 0;
}
- node = kmalloc(node_info.max_node_size, GFP_KERNEL);
+ node = pnpbios_kmalloc(node_info.max_node_size, GFP_KERNEL);
if (!node) return -ENOMEM;
- if ( pnp_bios_get_dev_node(&nodenum, boot, node) )
+ if ( pnpbios_get_dev_node(&nodenum, boot, node) )
return -EIO;
len = node->size - sizeof(struct pnp_bios_node);
memcpy(buf, node->data, len);
@@ -74,22 +74,25 @@
int boot = (long)data >> 8;
u8 nodenum = (long)data;

- node = kmalloc(node_info.max_node_size, GFP_KERNEL);
+ node = pnpbios_kmalloc(node_info.max_node_size, GFP_KERNEL);
if (!node) return -ENOMEM;
- if ( pnp_bios_get_dev_node(&nodenum, boot, node) )
+ if ( pnpbios_get_dev_node(&nodenum, boot, node) )
return -EIO;
if (count != node->size - sizeof(struct pnp_bios_node))
return -EINVAL;
memcpy(node->data, buf, count);
- if (pnp_bios_set_dev_node(node->handle, boot, node) != 0)
+ if (pnpbios_set_dev_node(node->handle, boot, node) != 0)
return -EINVAL;
kfree(node);
return count;
}

-static int pnp_proc_dont_use_current_config;
-
-void pnp_proc_init( int dont_use_current )
+/*
+ * When this is called, pnpbios functions are assumed to
+ * work and the pnpbios_dont_use_current_config flag
+ * should already have been set to the appropriate value
+ */
+void pnpbios_proc_init( void )
{
struct pnp_bios_node *node;
struct proc_dir_entry *ent;
@@ -97,10 +100,7 @@
int i;
u8 nodenum;

- pnp_proc_dont_use_current_config = dont_use_current;
-
- if (!pnp_bios_present()) return;
- if (pnp_bios_dev_node_info(&node_info) != 0) return;
+ if (pnpbios_dev_node_info(&node_info) != 0) return;

proc_pnp = proc_mkdir("pnp", proc_bus);
if (!proc_pnp) return;
@@ -108,13 +108,13 @@
if (!proc_pnp_boot) return;
create_proc_read_entry("devices", 0, proc_pnp, proc_read_devices, NULL);

- node = kmalloc(node_info.max_node_size, GFP_KERNEL);
+ node = pnpbios_kmalloc(node_info.max_node_size, GFP_KERNEL);
if (!node) return;
for (i=0,nodenum = 0; i<0xff && nodenum != 0xff; i++) {
- if (pnp_bios_get_dev_node(&nodenum, 1, node) != 0)
+ if (pnpbios_get_dev_node(&nodenum, 1, node) != 0)
break;
sprintf(name, "%02x", node->handle);
- if ( !pnp_proc_dont_use_current_config ) {
+ if ( !pnpbios_dont_use_current_config ) {
ent = create_proc_entry(name, 0, proc_pnp);
if (ent) {
ent->read_proc = proc_read_node;
@@ -132,7 +132,7 @@
kfree(node);
}

-void pnp_proc_done(void)
+void pnpbios_proc_done(void)
{
int i;
char name[3];
@@ -141,7 +141,7 @@

for (i=0; i<0xff; i++) {
sprintf(name, "%02x", i);
- if ( !pnp_proc_dont_use_current_config )
+ if ( !pnpbios_dont_use_current_config )
remove_proc_entry(name, proc_pnp);
remove_proc_entry(name, proc_pnp_boot);
}

2001-10-16 07:58:15

by Jörg Ziuber

[permalink] [raw]
Subject: Re: [PATCH] PnP BIOS patch against 2.4.12-ac2

Hi,

I tested the updated patch against 2.4.12-ac2 on a Sony Vaio PCG-FX205K.

You can see in the appendix output, no oops.

But, one Problem:
If I attach an USB device to the laptop it will not initialize and I get
the kernel messages, you will find in the last 10 lines of the output.
Amazing: If I cause permament traffic with a working device on IRQ 9
(e.g. a ping via eth0), the USB device will be recognized and works,
even though muuuuch slower.

Ideas ?

Bye,
--
J. Ziuber
[email protected]



APPENDIX:
---------
/var/log/boot.msg

...
<4>Local APIC disabled by BIOS -- reenabling.
<4>Found and enabled local APIC!
...
<6>Sony Vaio laptop detected.
<4>PCI: PCI BIOS revision 2.10 entry at 0xfd9b0, last bus=1
<4>PCI: Using configuration type 1
<4>PCI: Probing PCI hardware
<3>Unknown bridge resource 2: assuming transparent
<6>PCI: Using IRQ router PIIX [8086/244c] at 00:1f.0
<6>PnPBIOS: Found PnP BIOS installation structure at 0xc00f71a0.
<6>PnPBIOS: PnP BIOS version 1.0, entry 0xf0000:0x8f27, dseg 0x400.
<6>PnPBIOS: 20 nodes reported by PnP BIOS; 20 recorded by driver.
<4>PnPBIOS: PNP0c01: 0xe0000-0xfffff was already reserved
<4>PnPBIOS: PNP0c01: 0x100000-0xfbfffff was already reserved
<4>PnPBIOS: PNP0c02: 0x4d0-0x4d1 has been reserved
<4>PnPBIOS: PNP0c02: 0x1000-0x105f has been reserved
<4>PnPBIOS: PNP0c02: 0x1060-0x107f has been reserved
<4>PnPBIOS: PNP0c02: 0x1180-0x11bf has been reserved
<4>PnPBIOS: PNP0c02: 0xdc000-0xdffff was already reserved
<4>PnPBIOS: PNP0c02: 0xd8000-0xdbfff was already reserved
...
<6>PCI: Found IRQ 9 for device 00:1f.6
<6>PCI: Sharing IRQ 9 with 00:1f.3
<6>PCI: Sharing IRQ 9 with 00:1f.5
...

/proc/interrupts:

CPU0
0: 44393 XT-PIC timer
1: 3023 XT-PIC keyboard
2: 0 XT-PIC cascade
9: 9 XT-PIC eth0, usb-uhci, usb-uhci
12: 0 XT-PIC PS/2 Mouse
14: 3185 XT-PIC ide0
15: 1 XT-PIC ide1
NMI: 0
LOC: 44350
ERR: 0
MIS: 0


/var/log/messages:

Oct 16 09:18:58 shep syslogd 1.3-3: restart.
Oct 16 09:19:00 shep usbmgr[278]: start 0.4.6
Oct 16 09:19:00 shep usbmgr[280]: "usb-uhci" was loaded
Oct 16 09:19:00 shep usbmgr[295]: mount /proc/bus/usb
Oct 16 09:19:00 shep usbmgr[280]: class:0x9 subclass:0x0 protocol:0x0
Oct 16 09:19:01 shep usbmgr[280]: USB device is matched the
configuration
Oct 16 09:19:01 shep usbmgr[280]: "none" isn't loaded
Oct 16 09:19:01 shep rpc.statd[338]: Version 0.3.1 Starting
Oct 16 09:19:01 shep kernel: klogd 1.3-3, log source = /proc/kmsg
started.
Oct 16 09:19:01 shep kernel: Inspecting /boot/System.map
Oct 16 09:19:01 shep kernel: Symbol table has incorrect version number.
Oct 16 09:19:01 shep kernel: Inspecting /System.map
Oct 16 09:19:01 shep kernel: Loaded 13123 symbols from /System.map.
Oct 16 09:19:01 shep kernel: Symbols match kernel version 2.4.12.
Oct 16 09:19:01 shep kernel: Loaded 423 symbols from 7 modules.
Oct 16 09:19:01 shep kernel: eepro100.c:v1.09j-t 9/29/99 Donald Becker
http://cesdis.gsfc.nasa.gov/linux/drivers/eepro100.html
Oct 16 09:19:01 shep kernel: eepro100.c: $Revision: 1.36 $ 2000/11/17
Modified by Andrey V. Savochkin <[email protected]> and others
Oct 16 09:19:01 shep kernel: PCI: Found IRQ 9 for device 01:08.0
Oct 16 09:19:01 shep kernel: eth0: Intel Corporation 82820 (ICH2)
Chipset Ethernet Controller, 08:00:46:2B:FE:50, IRQ 9.
Oct 16 09:19:01 shep kernel: Board assembly 000000-000, Physical
connectors present: RJ45
Oct 16 09:19:01 shep kernel: Primary interface chip i82555 PHY #1.
Oct 16 09:19:01 shep kernel: General self-test: passed.
Oct 16 09:19:01 shep kernel: Serial sub-system self-test: passed.
Oct 16 09:19:01 shep kernel: Internal registers self-test: passed.
Oct 16 09:19:01 shep kernel: ROM checksum self-test: passed
(0x04f4518b).
Oct 16 09:19:01 shep kernel: IPv6 v0.8 for NET4.0
Oct 16 09:19:01 shep kernel: IPv6 over IPv4 tunneling driver
Oct 16 09:19:01 shep kernel: usb.c: registered new driver usbdevfs
Oct 16 09:19:01 shep kernel: usb.c: registered new driver hub
Oct 16 09:19:01 shep kernel: usb-uhci.c: $Revision: 1.268 $ time
09:11:00 Oct 16 2001
Oct 16 09:19:01 shep kernel: usb-uhci.c: High bandwidth mode enabled
Oct 16 09:19:01 shep kernel: PCI: Found IRQ 10 for device 00:1f.2
Oct 16 09:19:01 shep kernel: IRQ routing conflict for 00:1f.2, have irq
9, want irq 10
Oct 16 09:19:01 shep kernel: PCI: Setting latency timer of device
00:1f.2 to 64
Oct 16 09:19:01 shep kernel: usb-uhci.c: USB UHCI at I/O 0x1820, IRQ 9
Oct 16 09:19:01 shep kernel: usb-uhci.c: Detected 2 ports
Oct 16 09:19:01 shep kernel: usb.c: new USB bus registered, assigned bus
number 1
Oct 16 09:19:01 shep kernel: usb.c: kmalloc IF cf7aeb40, numif 1
Oct 16 09:19:01 shep kernel: usb.c: new device strings: Mfr=0,
Product=2, SerialNumber=1
Oct 16 09:19:01 shep kernel: usb.c: USB device number 1 default language
ID 0x0
Oct 16 09:19:01 shep kernel: Product: USB UHCI Root Hub
Oct 16 09:19:01 shep kernel: SerialNumber: 1820
Oct 16 09:19:01 shep kernel: hub.c: USB hub found
Oct 16 09:19:01 shep kernel: hub.c: 2 ports detected
Oct 16 09:19:01 shep kernel: hub.c: standalone hub
Oct 16 09:19:01 shep kernel: hub.c: ganged power switching
Oct 16 09:19:01 shep kernel: hub.c: global over-current protection
Oct 16 09:19:01 shep kernel: hub.c: Port indicators are not supported
Oct 16 09:19:01 shep kernel: hub.c: power on to power good time: 2ms
Oct 16 09:19:01 shep kernel: hub.c: hub controller current requirement:
0mA
Oct 16 09:19:01 shep kernel: hub.c: port removable status: RR
Oct 16 09:19:01 shep kernel: hub.c: local power source is good
Oct 16 09:19:01 shep kernel: hub.c: no over-current condition exists
Oct 16 09:19:01 shep kernel: hub.c: enabling power on all ports
Oct 16 09:19:01 shep kernel: usb.c: hub driver claimed interface
cf7aeb40
Oct 16 09:19:01 shep kernel: usb.c: kusbd: /sbin/hotplug add 1
Oct 16 09:19:01 shep kernel: usb.c: kusbd policy returned 0xfffffffe
Oct 16 09:19:01 shep kernel: PCI: Found IRQ 9 for device 00:1f.4
Oct 16 09:19:01 shep kernel: PCI: Setting latency timer of device
00:1f.4 to 64
Oct 16 09:19:01 shep kernel: usb-uhci.c: USB UHCI at I/O 0x2400, IRQ 9
Oct 16 09:19:01 shep kernel: usb-uhci.c: Detected 2 ports
Oct 16 09:19:01 shep kernel: usb.c: new USB bus registered, assigned bus
number 2
Oct 16 09:19:01 shep kernel: usb.c: kmalloc IF cf7aec60, numif 1
Oct 16 09:19:01 shep kernel: usb.c: new device strings: Mfr=0,
Product=2, SerialNumber=1
Oct 16 09:19:01 shep kernel: usb.c: USB device number 1 default language
ID 0x0
Oct 16 09:19:01 shep kernel: Product: USB UHCI Root Hub
Oct 16 09:19:01 shep kernel: SerialNumber: 2400
Oct 16 09:19:01 shep kernel: hub.c: USB hub found
Oct 16 09:19:01 shep kernel: hub.c: 2 ports detected
Oct 16 09:19:01 shep kernel: hub.c: standalone hub
Oct 16 09:19:01 shep kernel: hub.c: ganged power switching
Oct 16 09:19:01 shep kernel: hub.c: global over-current protection
Oct 16 09:19:01 shep kernel: hub.c: Port indicators are not supported
Oct 16 09:19:01 shep kernel: hub.c: power on to power good time: 2ms
Oct 16 09:19:01 shep kernel: hub.c: hub controller current requirement:
0mA
Oct 16 09:19:01 shep kernel: hub.c: port removable status: RR
Oct 16 09:19:01 shep kernel: hub.c: local power source is good
Oct 16 09:19:01 shep kernel: hub.c: no over-current condition exists
Oct 16 09:19:01 shep kernel: hub.c: enabling power on all ports
Oct 16 09:19:01 shep kernel: usb.c: hub driver claimed interface
cf7aec60
Oct 16 09:19:01 shep kernel: usb.c: kusbd: /sbin/hotplug add 1
Oct 16 09:19:01 shep kernel: usb.c: kusbd policy returned 0xfffffffe
Oct 16 09:19:01 shep kernel: usb-uhci.c: v1.268:USB Universal Host
Controller Interface driver
Oct 16 09:19:01 shep kernel: Installing knfsd (copyright (C) 1996
[email protected]).
Oct 16 09:19:02 shep /usr/sbin/cron[403]: (CRON) STARTUP (fork ok)
Oct 16 09:19:03 shep /sbin/SuSEpersonal-firewall: SuSEpersonal-firewall:
Loading of module ipchains was not successful.
Oct 16 09:19:03 shep /sbin/SuSEpersonal-firewall: Aborting. No action
taken.
Oct 16 09:19:09 shep kernel: eth0: no IPv6 routers present
Oct 16 09:20:24 shep kernel: hub.c: port 2 connection change
Oct 16 09:20:24 shep kernel: hub.c: port 2, portstatus 101, change 1, 12
Mb/s
Oct 16 09:20:24 shep kernel: hub.c: port 2, portstatus 103, change 0, 12
Mb/s
Oct 16 09:20:24 shep kernel: hub.c: USB new device connect on bus1/2,
assigned device number 2
Oct 16 09:20:27 shep kernel: usb_control/bulk_msg: timeout
Oct 16 09:20:27 shep kernel: usb.c: USB device not accepting new
address=2 (error=-110)
Oct 16 09:20:27 shep kernel: hub.c: port 2, portstatus 103, change 0, 12
Mb/s
Oct 16 09:20:27 shep kernel: hub.c: USB new device connect on bus1/2,
assigned device number 3
Oct 16 09:20:30 shep kernel: usb_control/bulk_msg: timeout
Oct 16 09:20:30 shep kernel: usb.c: USB device not accepting new
address=3 (error=-110)

2001-10-16 21:44:44

by Thomas Hood

[permalink] [raw]
Subject: Re: [PATCH] PnP BIOS patch against 2.4.12-ac2

On Tue, 2001-10-16 at 03:58, J?rg Ziuber wrote:
> I tested the updated patch against 2.4.12-ac2 on a Sony Vaio PCG-FX205K.
> You can see in the appendix output, no oops.
>
> But, one Problem:
> If I attach an USB device to the laptop it will not initialize and I get
> the kernel messages, you will find in the last 10 lines of the output.
> Amazing: If I cause permament traffic with a working device on IRQ 9
> (e.g. a ping via eth0), the USB device will be recognized and works,
> even though muuuuch slower.

Is this problem related to the PnP BIOS patch? That is,
do you have the same problem with a kernel that lacks the
patch?


2001-10-17 02:49:48

by Steven A. DuChene

[permalink] [raw]
Subject: Re: [PATCH] PnP BIOS -- bugfix; update devlist on setpnp

Thomas:
Just to let you know I still have the same problem with a resource conflict
between the PnPBIOS code and the i2c/lm_sensors stuff at 1040 with this
latest patch. Again, this is on a Intel Lancewood (L440GX) motherboard.
I also have a system with a Intel STL2 motherboard (successor to the
Lancewood) so I will test that under the same conditions later tonight.

modprobe i2c-piix4
/lib/modules/2.4.10-ac12/kernel/drivers/i2c/i2c-piix4.o: init_module: No such device
Hint: insmod errors can be caused by incorrect module parameters, including invalid IO or IRQ parameters
/lib/modules/2.4.10-ac12/kernel/drivers/i2c/i2c-piix4.o: insmod /lib/modules/2.4.10-ac12/kernel/drivers/i2c/i2c-piix4.o failed
/lib/modules/2.4.10-ac12/kernel/drivers/i2c/i2c-piix4.o: insmod i2c-piix4 failed


dmesg

.
.
.
i2c-piix4.o version 2.6.1 (20010830)
i2c-piix4.o: Found PIIX4 device
i2c-piix4.o: SMB region 0x1040 already in use!
i2c-piix4.o: Device not detected, module not inserted.


cat /proc/ioports
.
.
.
0c00-0c3f : Intel Corporation 82371AB PIIX4 ACPI
0c00-0c3f : PnPBIOS PNP0c02
0ca0-0ca3 : PnPBIOS PNP0c02
0cb8-0cbf : PnPBIOS PNP0c02
0cf8-0cff : PCI conf1
1000-103f : PnPBIOS PNP0c02
1040-105f : Intel Corporation 82371AB PIIX4 ACPI
1040-104f : PnPBIOS PNP0c02
.
.
.

--
Steven A. DuChene [email protected]
[email protected]
[email protected]

http://www.mindspring.com/~sduchene/

2001-10-17 03:15:15

by Thomas Hood

[permalink] [raw]
Subject: Re: [PATCH] PnP BIOS -- bugfix; update devlist on setpnp

> Thomas:
> Just to let you know I still have the same problem with a resource
> conflict between the PnPBIOS code and the i2c/lm_sensors stuff at
> 1040 with this latest patch.

Yep, I know. I haven't addressed this bug in any of the
patches I've submitted to l-k. I'd like to fix it, but
I don't know how yet: I have only a partial understanding of
how resource allocation works.

Thanks for testing yesterday's PnP BIOS patch.

--
Thomas

2001-10-17 06:28:38

by Jörg Ziuber

[permalink] [raw]
Subject: Re: [PATCH] PnP BIOS patch against 2.4.12-ac2

Thomas Hood wrote:
>
> On Tue, 2001-10-16 at 03:58, J?rg Ziuber wrote:
> > I tested the updated patch against 2.4.12-ac2 on a Sony Vaio PCG-FX205K.
> > You can see in the appendix output, no oops.
> >
> > But, one Problem:
> > If I attach an USB device to the laptop it will not initialize and I get
> > the kernel messages, you will find in the last 10 lines of the output.
> > Amazing: If I cause permament traffic with a working device on IRQ 9
> > (e.g. a ping via eth0), the USB device will be recognized and works,
> > even though muuuuch slower.
>
> Is this problem related to the PnP BIOS patch? That is,
> do you have the same problem with a kernel that lacks the
> patch?

Maybe it is related.
This is at least a Sony Vaio problem, because attaching the same USB
device to other PCs with the same (kernel)installation works without
problems.
It was checked to be USB-device-independent with the Vaio (same problem
with any device).
Because USB even works on the Vaio under Windows, the USB developers
(uhci) told me to look in linux-kernel for the PCI/IRQ programmers due
to a potentially broken BIOS ("IRQ routing problem")- that's where I am
now (?).

A kernel without the patch results in the same non-recognition
(non-USB-number-assignment) of the USB device, but when booting I get
errors concerning a multiple reservation of IRQ9. With the patch there
are no errors of that kind (see last mail). And the "feature", that USB
works when the shared interrupt is busy (same effect with unpatched
kernel), makes me feel that there is a IRQ problem, specific to Sony
Vaio. So, the PnP-BIOS-patch is my hope because it cares about Sony Vaio
(BIOS/IRQ?) specials.

Very hopefully,
--
J. Ziuber
[email protected]

2001-10-17 08:10:14

by Steven A. DuChene

[permalink] [raw]
Subject: Re: [PATCH] PnP BIOS -- bugfix; update devlist on setpnp

OK, I tried this with the Intel STL2 motherboard I also have and I got
a similar error when trying to load the correct i2c bus module when the
PnPBIOS stuff is compiled into the kernel.

modprobe i2c-piix4
/lib/modules/2.4.10-ac12pnp/kernel/drivers/i2c/i2c-piix4.o: init_module: No such device
Hint: insmod errors can be caused by incorrect module parameters, including invalid IO or IRQ parameters
/lib/modules/2.4.10-ac12pnp/kernel/drivers/i2c/i2c-piix4.o: insmod /lib/modules/2.4.10-ac12pnp/kernel/drivers/i2c/i2c-piix4.o failed
/lib/modules/2.4.10-ac12pnp/kernel/drivers/i2c/i2c-piix4.o: insmod i2c-piix4 failed


dmesg
.
.
.
i2c-piix4.o version 2.6.1 (20010830)
i2c-piix4.o: Found OSB4 device
i2c-piix4.o: SMB region 0x580 already in use!
i2c-piix4.o: Device not detected, module not inserted.


cat /proc/ioports
.
.
.
04d0-04d1 : PnPBIOS PNP0c02
0580-058f : PnPBIOS PNP0c02
0840-084f : ServerWorks OSB4 IDE Controller
0840-0847 : ide0
0848-084f : ide1
0cd6-0cd7 : PnPBIOS PNP0c02
0cf8-0cff : PCI conf1
5000-50ff : ATI Technologies Inc 3D Rage IIC 215IIC [Mach64 GT IIC]
5400-543f : Intel Corporation 82557 [Ethernet Pro 100]
5400-543f : eepro100
5440-547f : Intel Corporation 82557 [Ethernet Pro 100] (#2)
5440-547f : eepro100
5800-58ff : Adaptec 7899P
6000-60ff : Adaptec 7899P (#2)
fe00-fe3f : PnPBIOS PNP0c02


So this is a problem on more than just those old Intel Lancewood L440GX
motherboards. The STL2 is a fairly recent dual processor motherboard
--
Steven A. DuChene [email protected]
[email protected]
[email protected]

http://www.mindspring.com/~sduchene/

2001-10-17 13:36:09

by Thomas Hood

[permalink] [raw]
Subject: Re: [PATCH] PnP BIOS -- bugfix; update devlist on setpnp

On Wed, 2001-10-17 at 04:10, Steven A. DuChene wrote:
> OK, I tried this with the Intel STL2 motherboard I also have and I got
> a similar error when trying to load the correct i2c bus module when the
> PnPBIOS stuff is compiled into the kernel.

Understood.

I'd just like to reiterate that my patch isn't the cause
of your problem. It's just that my patch doesn't address
your problem. IIUC.

I provided a "workaround patch" before. Can you continue
to use that for the time being?

I'd like to make a promise that I'll submit a new patch
soon that will address your problem; however I don't yet know
exactly how to go about addressing it.

--
Thomas

2001-10-17 13:41:49

by Thomas Hood

[permalink] [raw]
Subject: Re: [PATCH] PnP BIOS patch against 2.4.12-ac2

On Wed, 2001-10-17 at 02:28, J?rg Ziuber wrote:
> Thomas Hood wrote:
> > Is this problem related to the PnP BIOS patch? That is,
> > do you have the same problem with a kernel that lacks the
> > patch?
>
> Maybe it is related.
> This is at least a Sony Vaio problem, because attaching the same USB
> device to other PCs with the same (kernel)installation works without
> problems.
> It was checked to be USB-device-independent with the Vaio (same problem
> with any device).
> Because USB even works on the Vaio under Windows, the USB developers
> (uhci) told me to look in linux-kernel for the PCI/IRQ programmers due
> to a potentially broken BIOS ("IRQ routing problem")- that's where I am
> now (?).
>
> A kernel without the patch results in the same non-recognition
> (non-USB-number-assignment) of the USB device, but when booting I get
> errors concerning a multiple reservation of IRQ9. With the patch there
> are no errors of that kind (see last mail).

That puzzles me. I'm not sure how my patch could affect
IRQ handling. Could you please try the version of the
patch that I submitted last night under the title
"[PATCH] PnP BIOS -- new"? Let me know whether you do
or you do not get the error messages concerning multiple
reservations of IRQ9.

> And the "feature", that USB
> works when the shared interrupt is busy (same effect with unpatched
> kernel), makes me feel that there is a IRQ problem, specific to Sony
> Vaio. So, the PnP-BIOS-patch is my hope because it cares about Sony Vaio
> (BIOS/IRQ?) specials.

I wouldn't hope too strongly that my patch will help you.

Just to be clear. IIUC you are saying that my patch isn't
the cause of your problem; it's just that it doesn't solve
your problem. Is that right?

--
Thomas




2001-10-17 14:43:20

by Jörg Ziuber

[permalink] [raw]
Subject: Re: [PATCH] PnP BIOS patch against 2.4.12-ac2

Thomas Hood wrote:

> Just to be clear. IIUC you are saying that my patch isn't
> the cause of your problem; it's just that it doesn't solve
> your problem. Is that right?
Exactly.
As I understand you, it's not made to solve my problem - but, who else
can help me ?

The "IRQ error" output with/without your last patch is to come later.

Bye,
--
J?rg Ziuber Institut f?r Chemische Technik
Universit?t Karlsruhe
[email protected] Kaiserstrasse 12
Tel. 0721 / 608-2399 76128 Karlsruhe

2001-10-17 16:04:06

by Gunther.Mayer

[permalink] [raw]
Subject: Re: [PATCH] PnP BIOS -- bugfix; update devlist on setpnp

"Steven A. DuChene" wrote:
>
> OK, I tried this with the Intel STL2 motherboard I also have and I got
> a similar error when trying to load the correct i2c bus module when the
> PnPBIOS stuff is compiled into the kernel.
>
> modprobe i2c-piix4
> /lib/modules/2.4.10-ac12pnp/kernel/drivers/i2c/i2c-piix4.o: init_module: No such device
> Hint: insmod errors can be caused by incorrect module parameters, including invalid IO or IRQ >parameters

i2c-piix4 has to be taught to ignore PNP0c0x reservations.

PNP0C02 means "mainboard resource" and obviously i2c-piix4
would like to use it, so it should make use of it's knowledge.

As "mainboard resouce" is very generic we must reserve it
to protect against mapping other addresses over it.

2001-10-17 16:08:06

by Steven A. DuChene

[permalink] [raw]
Subject: Re: [PATCH] PnP BIOS -- bugfix; update devlist on setpnp

On Wed, Oct 17, 2001 at 09:35:34AM -0400, Thomas Hood wrote:
> On Wed, 2001-10-17 at 04:10, Steven A. DuChene wrote:
> > OK, I tried this with the Intel STL2 motherboard I also have and I got
> > a similar error when trying to load the correct i2c bus module when the
> > PnPBIOS stuff is compiled into the kernel.
>
> Understood.
>
> I'd just like to reiterate that my patch isn't the cause
> of your problem. It's just that my patch doesn't address
> your problem. IIUC.

Yes, I understood that from the start of all of this but you seemed to be
be the only person messing with the PnPBIOS code so I thought you might be
interested in this annomoly. I appreciate the info/help you have provided
so far.

>
> I provided a "workaround patch" before. Can you continue
> to use that for the time being?
>

Yes, but according to these latest results that work around of skipping a
particular ioport would have to be different for each motherboard with this
problem. There must be a better way to do this.

> I'd like to make a promise that I'll submit a new patch
> soon that will address your problem; however I don't yet know
> exactly how to go about addressing it.
>

Perhaps someone else can provide us a hint or two as to where to start. :-)
--
Steven A. DuChene [email protected]
[email protected]
[email protected]

http://www.mindspring.com/~sduchene/

2001-10-17 20:43:45

by Thomas Hood

[permalink] [raw]
Subject: Re: [PATCH] PnP BIOS patch against 2.4.12-ac2

On Wed, 2001-10-17 at 10:43, J?rg Ziuber wrote:
> Thomas Hood wrote:
> > Just to be clear. IIUC you are saying that my patch isn't
> > the cause of your problem; it's just that it doesn't solve
> > your problem. Is that right?
> Exactly.
> As I understand you, it's not made to solve my problem

Correct.


2001-10-17 20:59:16

by Thomas Hood

[permalink] [raw]
Subject: Re: [PATCH] PnP BIOS -- bugfix; update devlist on setpnp

On Wed, 2001-10-17 at 12:04, Gunther Mayer wrote:
> i2c-piix4 has to be taught to ignore PNP0c0x reservations.
>
> PNP0C02 means "mainboard resource" and obviously i2c-piix4
> would like to use it, so it should make use of it's knowledge.
>
> As "mainboard resouce" is very generic we must reserve it
> to protect against mapping other addresses over it.

Your approach would work. But ...

Alan has said that the thing to do is mark these resources
as extant but unused. I presume one does this by calling
request_resource with appropriate flags [un]set.

Thomas