Skip to contentSkip to conversation

PNP: convert resource options to unified dynamic list, v1

PATCH In review Bjorn Helgaas 2 participants 46 messages May 30, 2008 – Jun 4, 2008

Subsystems (3)
lore
Share & tools
lore
#0 lore raw

cover PNP: convert resource options to unified dynamic list, v1

This patch series converts the PNP resource option structures to a unified linked list. This preserves resource order, which is important for some devices. There's more detail in the comments for the last patch.

Any comments would be welcome.

This depends on some patches that are in -mm, but not yet upstream. In mmotm, these would probably go after pnp-dont-sort-by-type-in-sys-resources.patch

Bjorn

#1 lore raw

PATCH 1/15 serial: when guessing, check only active resources, not options

Given a completely unknown PNP device, if it happens to have a modem-like string in its name and it matches a COM port address, we assume it's a modem.

We used to check the address against all the possible resource options for the device. But the device is already configured and enabled, so we only need to check the resources it is actually using. If we matched an address that wasn't currently enabled, we would fail anyway as soon as we attempted to touch the device at that address.

This removes a reference to the struct pnp_dev.{independent,dependent} fields, which I will soon make private to the PNP subsystem.

drivers/serial/8250_pnp.c +11 -17
Index: work10/drivers/serial/8250_pnp.c
===================================================================
@@ -383,22 +383,19 @@ static int __devinit check_name(char *na
 	return 0;
 }
 
-static int __devinit check_resources(struct pnp_option *option)
+static int __devinit check_resources(struct pnp_dev *dev)
 {
-	struct pnp_option *tmp;
-	if (!option)
+	resource_size_t port, size;
+
+	if (!pnp_port_valid(dev, 0))
 		return 0;
 
-	for (tmp = option; tmp; tmp = tmp->next) {
-		struct pnp_port *port;
-		for (port = tmp->port; port; port = port->next)
-			if ((port->size == 8) &&
-			    ((port->min == 0x2f8) ||
-			     (port->min == 0x3f8) ||
-			     (port->min == 0x2e8) ||
-			     (port->min == 0x3e8)))
-				return 1;
-	}
+	port = pnp_port_start(dev, 0);
+	size = pnp_port_len(dev, 0);
+
+	if (size == 8 &&
+	    (port == 0x2f8 || port == 0x3f8 || port == 0x2e8 || port == 0x3e8))
+		return 1;
 
 	return 0;
 }
@@ -420,10 +417,7 @@ static int __devinit serial_pnp_guess_bo
 		(dev->card && check_name(dev->card->name))))
 			return -ENODEV;
 
-	if (check_resources(dev->independent))
-		return 0;
-
-	if (check_resources(dev->dependent))
+	if (check_resources(dev))
 		return 0;
 
 	return -ENODEV;
#2 lore raw

Re: [patch 01/15] serial: when guessing, check only active resources, not options

Quoted 11 lines · Bjorn Helgaas

Given a completely unknown PNP device, if it happens to have a modem-like string in its name and it matches a COM port address, we assume it's a modem.

We used to check the address against all the possible resource options for the device. But the device is already configured and enabled, so we only need to check the resources it is actually using. If we matched an address that wasn't currently enabled, we would fail anyway as soon as we attempted to touch the device at that address.

Quoted 4 lines

This removes a reference to the struct pnp_dev.{independent,dependent} fields, which I will soon make private to the PNP subsystem.

This isn't quite right it seems. Or changes behaviour at least:

Quoted 39 lines

Index: work10/drivers/serial/8250_pnp.c
===================================================================

drivers/serial/8250_pnp.c +10 -13
@@ -383,22 +383,19 @@ static int __devinit check_name(char *na
 	return 0;
 }
 
-static int __devinit check_resources(struct pnp_option *option)
+static int __devinit check_resources(struct pnp_dev *dev)
 {
-	struct pnp_option *tmp;
-	if (!option)
+	resource_size_t port, size;
+
+	if (!pnp_port_valid(dev, 0))
 		return 0;
 
-	for (tmp = option; tmp; tmp = tmp->next) {
-		struct pnp_port *port;
-		for (port = tmp->port; port; port = port->next)
-			if ((port->size == 8) &&
-			    ((port->min == 0x2f8) ||
-			     (port->min == 0x3f8) ||
-			     (port->min == 0x2e8) ||
-			     (port->min == 0x3e8)))
-				return 1;
-	}
+	port = pnp_port_start(dev, 0);
+	size = pnp_port_len(dev, 0);
+
+	if (size == 8 &&
+	    (port == 0x2f8 || port == 0x3f8 || port == 0x2e8 || port == 0x3e8))
+		return 1;
 
 	return 0;
 }
@@ -420,10 +417,7 @@ static int __devinit serial_pnp_guess_bo
 		(dev->card && check_name(dev->card->name))))

drivers/serial/8250_pnp.c static int __devinit serial_pnp_guess_bo · line 423

Quoted 10 lines
drivers/serial/8250_pnp.c +1 -4
 			return -ENODEV;
 
-	if (check_resources(dev->independent))
-		return 0;
-
-	if (check_resources(dev->dependent))
+	if (check_resources(dev))
 		return 0;
 
 	return -ENODEV;

We used to cry "modem" if the device _could_ be configured using a COM address while after this change we'd only do so if it _was_ configured using one.

My old analog modem for example had 5 dependent sets -- the first with the regular COM port addresses (0x3f8, 0x2f8, 0x3e8, 0x2e8) and a 5th one listing a port range of (IIRC, something like that at least) 0x100 to 0xff8.

So say I'd have a PC with the regular two onboard COM ports at COM1 and COM2 (0x3f8 and 0x2f8) and an additional serial controller providing COM3 and COM4 (0x3e8 and 0x2e8). My modem would then be configured to use 0x100 and this code would no longer trigger while it did use to.

Not that I care deeply or anything but whomever wrote this did no doubt intend it to work this way...

Rene.

#3 lore raw

Re: [patch 01/15] serial: when guessing, check only active resources, not options

Quoted 9 lines · Rene Herman

We used to cry "modem" if the device _could_ be configured using a COM address while after this change we'd only do so if it _was_ configured using one.

My old analog modem for example had 5 dependent sets -- the first with the regular COM port addresses (0x3f8, 0x2f8, 0x3e8, 0x2e8) and a 5th one listing a port range of (IIRC, something like that at least) 0x100 to 0xff8.

Quoted 4 lines

So say I'd have a PC with the regular two onboard COM ports at COM1 and COM2 (0x3f8 and 0x2f8) and an additional serial controller providing COM3 and COM4 (0x3e8 and 0x2e8). My modem would then be configured to use 0x100 and this code would no longer trigger while it did use to.

Ah, you're right. That scenario hadn't occurred to me. Let me see if I can figure out a way to make that work again.

Bjorn

#4 lore raw

PATCH 2/15 PNP: whitespace/coding style fixes

In reply to Bjorn Helgaas

No functional change; just make a couple declarations consistent with the rest of the file.

drivers/pnp/interface.c +8 -7
Index: work10/drivers/pnp/interface.c
===================================================================
@@ -216,12 +216,12 @@ static ssize_t pnp_show_options(struct d
 				struct device_attribute *attr, char *buf)
 {
 	struct pnp_dev *dev = to_pnp_dev(dmdev);
+	pnp_info_buffer_t *buffer;
 	struct pnp_option *independent = dev->independent;
 	struct pnp_option *dependent = dev->dependent;
 	int ret, dep = 1;
 
-	pnp_info_buffer_t *buffer = (pnp_info_buffer_t *)
-	    pnp_alloc(sizeof(pnp_info_buffer_t));
+	buffer = pnp_alloc(sizeof(pnp_info_buffer_t));
 	if (!buffer)
 		return -ENOMEM;
 
@@ -248,17 +248,18 @@ static ssize_t pnp_show_current_resource
 					  char *buf)
 {
 	struct pnp_dev *dev = to_pnp_dev(dmdev);
+	pnp_info_buffer_t *buffer;
 	struct pnp_resource *pnp_res;
 	struct resource *res;
 	int ret;
-	pnp_info_buffer_t *buffer;
 
 	if (!dev)
 		return -EINVAL;
 
-	buffer = (pnp_info_buffer_t *) pnp_alloc(sizeof(pnp_info_buffer_t));
+	buffer = pnp_alloc(sizeof(pnp_info_buffer_t));
 	if (!buffer)
 		return -ENOMEM;
+
 	buffer->len = PAGE_SIZE;
 	buffer->buffer = buf;
 	buffer->curr = buffer->buffer;
@@ -295,9 +296,9 @@ static ssize_t pnp_show_current_resource
 	return ret;
 }
 
-static ssize_t
-pnp_set_current_resources(struct device *dmdev, struct device_attribute *attr,
-			  const char *ubuf, size_t count)
+static ssize_t pnp_set_current_resources(struct device *dmdev,
+					 struct device_attribute *attr,
+					 const char *ubuf, size_t count)
 {
 	struct pnp_dev *dev = to_pnp_dev(dmdev);
 	char *buf = (void *)ubuf;
Acked-by on v1 2/15
#5 lore raw

Re: [patch 02/15] PNP: whitespace/coding style fixes

Quoted 4 lines · Bjorn Helgaas

No functional change; just make a couple declarations consistent with the rest of the file.

By the way, noticed recently that Acked-by might not be the right tag given that I'm not in any formal acking path or anything; feel free to translate them into any tag of your liking. They're meant as "looked at this and agree".

Rene.

#6 lore raw

PATCH 3/15 PNP: define PNP-specific IORESOURCE_IO_* flags alongside IRQ, DMA, MEM

In reply to Bjorn Helgaas

PNP previously defined PNP_PORT_FLAG_16BITADDR and PNP_PORT_FLAG_FIXED in a private header file, but put those flags in struct resource.flags fields. Better to make them IORESOURCE_IO_* flags like the existing IRQ, DMA, and MEM flags.

---
 include/linux/ioport.h         |   10 +++++++---
 include/linux/pnp.h            |    3 ---
 drivers/pnp/interface.c        |    2 +-
 drivers/pnp/isapnp/core.c      |    4 ++--
 drivers/pnp/pnpacpi/rsparser.c |   10 +++++-----
 drivers/pnp/pnpbios/rsparser.c |    4 ++--
 6 files changed, 17 insertions(+), 16 deletions(-)
include/linux/ioport.h +5 -1
Index: work10/include/linux/ioport.h
===================================================================
@@ -76,7 +76,7 @@ struct resource_list {
 #define IORESOURCE_DMA_TYPEB		(2<<6)
 #define IORESOURCE_DMA_TYPEF		(3<<6)
 
-/* ISA PnP memory I/O specific bits (IORESOURCE_BITS) */
+/* ISA PnP memory specific bits (IORESOURCE_BITS) */
 #define IORESOURCE_MEM_WRITEABLE	(1<<0)	/* dup: IORESOURCE_READONLY */
 #define IORESOURCE_MEM_CACHEABLE	(1<<1)	/* dup: IORESOURCE_CACHEABLE */
 #define IORESOURCE_MEM_RANGELENGTH	(1<<2)	/* dup: IORESOURCE_RANGELENGTH */
@@ -88,6 +88,10 @@ struct resource_list {
 #define IORESOURCE_MEM_SHADOWABLE	(1<<5)	/* dup: IORESOURCE_SHADOWABLE */
 #define IORESOURCE_MEM_EXPANSIONROM	(1<<6)
 
+/* ISA PnP I/O specific bits (IORESOURCE_BITS) */
+#define IORESOURCE_IO_16BIT_ADDR	(1<<0)
+#define IORESOURCE_IO_FIXED		(1<<1)
+
 /* PCI ROM control bits (IORESOURCE_BITS) */
 #define IORESOURCE_ROM_ENABLE		(1<<0)	/* ROM is enabled, same as PCI_ROM_ADDRESS_ENABLE */
 #define IORESOURCE_ROM_SHADOW		(1<<1)	/* ROM is copy at C000:0 */
include/linux/pnp.h +0 -3
Index: work10/include/linux/pnp.h
===================================================================
@@ -175,9 +175,6 @@ static inline int pnp_dma_valid(struct p
 }
 
 
-#define PNP_PORT_FLAG_16BITADDR	(1<<0)
-#define PNP_PORT_FLAG_FIXED	(1<<1)
-
 struct pnp_port {
 	unsigned short min;	/* min base number */
 	unsigned short max;	/* max base number */
drivers/pnp/interface.c +1 -1
Index: work10/drivers/pnp/interface.c
===================================================================
@@ -57,7 +57,7 @@ static void pnp_print_port(pnp_info_buff
 		   "%sport 0x%x-0x%x, align 0x%x, size 0x%x, %i-bit address decoding\n",
 		   space, port->min, port->max,
 		   port->align ? (port->align - 1) : 0, port->size,
-		   port->flags & PNP_PORT_FLAG_16BITADDR ? 16 : 10);
+		   port->flags & IORESOURCE_IO_16BIT_ADDR ? 16 : 10);
 }
 
 static void pnp_print_irq(pnp_info_buffer_t * buffer, char *space,
drivers/pnp/isapnp/core.c +2 -2
Index: work10/drivers/pnp/isapnp/core.c
===================================================================
@@ -486,7 +486,7 @@ static void __init isapnp_parse_port_res
 	port->max = (tmp[4] << 8) | tmp[3];
 	port->align = tmp[5];
 	port->size = tmp[6];
-	port->flags = tmp[0] ? PNP_PORT_FLAG_16BITADDR : 0;
+	port->flags = tmp[0] ? IORESOURCE_IO_16BIT_ADDR : 0;
 	pnp_register_port_resource(dev, option, port);
 }
 
@@ -507,7 +507,7 @@ static void __init isapnp_parse_fixed_po
 	port->min = port->max = (tmp[1] << 8) | tmp[0];
 	port->size = tmp[2];
 	port->align = 0;
-	port->flags = PNP_PORT_FLAG_FIXED;
+	port->flags = IORESOURCE_IO_FIXED;
 	pnp_register_port_resource(dev, option, port);
 }
 
drivers/pnp/pnpacpi/rsparser.c +5 -5
Index: work10/drivers/pnp/pnpacpi/rsparser.c
===================================================================
@@ -178,7 +178,7 @@ static void pnpacpi_parse_allocated_iore
 	u64 end = start + len - 1;
 
 	if (io_decode == ACPI_DECODE_16)
-		flags |= PNP_PORT_FLAG_16BITADDR;
+		flags |= IORESOURCE_IO_16BIT_ADDR;
 	if (len == 0 || end >= 0x10003)
 		flags |= IORESOURCE_DISABLED;
 
@@ -451,7 +451,7 @@ static __init void pnpacpi_parse_port_op
 	port->align = io->alignment;
 	port->size = io->address_length;
 	port->flags = ACPI_DECODE_16 == io->io_decode ?
-	    PNP_PORT_FLAG_16BITADDR : 0;
+	    IORESOURCE_IO_16BIT_ADDR : 0;
 	pnp_register_port_resource(dev, option, port);
 }
 
@@ -469,7 +469,7 @@ static __init void pnpacpi_parse_fixed_p
 	port->min = port->max = io->address;
 	port->size = io->address_length;
 	port->align = 0;
-	port->flags = PNP_PORT_FLAG_FIXED;
+	port->flags = IORESOURCE_IO_FIXED;
 	pnp_register_port_resource(dev, option, port);
 }
 
@@ -575,7 +575,7 @@ static __init void pnpacpi_parse_address
 		port->min = port->max = p->minimum;
 		port->size = p->address_length;
 		port->align = 0;
-		port->flags = PNP_PORT_FLAG_FIXED;
+		port->flags = IORESOURCE_IO_FIXED;
 		pnp_register_port_resource(dev, option, port);
 	}
 }
@@ -890,7 +890,7 @@ static void pnpacpi_encode_io(struct pnp
 	struct acpi_resource_io *io = &resource->data.io;
 
 	/* Note: pnp_assign_port will copy pnp_port->flags into p->flags */
-	io->io_decode = (p->flags & PNP_PORT_FLAG_16BITADDR) ?
+	io->io_decode = (p->flags & IORESOURCE_IO_16BIT_ADDR) ?
 	    ACPI_DECODE_16 : ACPI_DECODE_10;
 	io->minimum = p->start;
 	io->maximum = p->end;
drivers/pnp/pnpbios/rsparser.c +2 -2
Index: work10/drivers/pnp/pnpbios/rsparser.c
===================================================================
@@ -310,7 +310,7 @@ static __init void pnpbios_parse_port_op
 	port->max = (p[5] << 8) | p[4];
 	port->align = p[6];
 	port->size = p[7];
-	port->flags = p[1] ? PNP_PORT_FLAG_16BITADDR : 0;
+	port->flags = p[1] ? IORESOURCE_IO_16BIT_ADDR : 0;
 	pnp_register_port_resource(dev, option, port);
 }
 
@@ -326,7 +326,7 @@ static __init void pnpbios_parse_fixed_p
 	port->min = port->max = (p[2] << 8) | p[1];
 	port->size = p[3];
 	port->align = 0;
-	port->flags = PNP_PORT_FLAG_FIXED;
+	port->flags = IORESOURCE_IO_FIXED;
 	pnp_register_port_resource(dev, option, port);
 }
 
Acked-by on v1 3/15
#7 lore raw

Re: [patch 03/15] PNP: define PNP-specific IORESOURCE_IO_* flags alongside IRQ, DMA, MEM

Quoted 6 lines · Bjorn Helgaas

PNP previously defined PNP_PORT_FLAG_16BITADDR and PNP_PORT_FLAG_FIXED in a private header file, but put those flags in struct resource.flags fields. Better to make them IORESOURCE_IO_* flags like the existing IRQ, DMA, and MEM flags.

Wondered a bit since only PnPACPI seems to directly encode those flags to a res->flags (as opposed to a port->flags) but pnp_assign_port() copies them over verbatim indeed...

Rene.

#8 lore raw

PATCH 4/15 PNP: make resource option structures private to PNP subsystem

In reply to Bjorn Helgaas

Nothing outside the PNP subsystem should need access to a device's resource options, so this patch moves the option structure declarations to a private header file.

drivers/pnp/base.h +48 -0
Index: work10/drivers/pnp/base.h
===================================================================
@@ -19,6 +19,54 @@ void pnp_remove_card(struct pnp_card *ca
 int pnp_add_card_device(struct pnp_card *card, struct pnp_dev *dev);
 void pnp_remove_card_device(struct pnp_dev *dev);
 
+struct pnp_port {
+	unsigned short min;	/* min base number */
+	unsigned short max;	/* max base number */
+	unsigned char align;	/* align boundary */
+	unsigned char size;	/* size of range */
+	unsigned char flags;	/* port flags */
+	unsigned char pad;	/* pad */
+	struct pnp_port *next;	/* next port */
+};
+
+#define PNP_IRQ_NR 256
+struct pnp_irq {
+	DECLARE_BITMAP(map, PNP_IRQ_NR);	/* bitmask for IRQ lines */
+	unsigned char flags;	/* IRQ flags */
+	unsigned char pad;	/* pad */
+	struct pnp_irq *next;	/* next IRQ */
+};
+
+struct pnp_dma {
+	unsigned char map;	/* bitmask for DMA channels */
+	unsigned char flags;	/* DMA flags */
+	struct pnp_dma *next;	/* next port */
+};
+
+struct pnp_mem {
+	unsigned int min;	/* min base number */
+	unsigned int max;	/* max base number */
+	unsigned int align;	/* align boundary */
+	unsigned int size;	/* size of range */
+	unsigned char flags;	/* memory flags */
+	unsigned char pad;	/* pad */
+	struct pnp_mem *next;	/* next memory resource */
+};
+
+#define PNP_RES_PRIORITY_PREFERRED	0
+#define PNP_RES_PRIORITY_ACCEPTABLE	1
+#define PNP_RES_PRIORITY_FUNCTIONAL	2
+#define PNP_RES_PRIORITY_INVALID	65535
+
+struct pnp_option {
+	unsigned short priority;	/* priority */
+	struct pnp_port *port;		/* first port */
+	struct pnp_irq *irq;		/* first IRQ */
+	struct pnp_dma *dma;		/* first DMA */
+	struct pnp_mem *mem;		/* first memory resource */
+	struct pnp_option *next;	/* used to chain dependent resources */
+};
+
 struct pnp_option *pnp_build_option(int priority);
 struct pnp_option *pnp_register_independent_option(struct pnp_dev *dev);
 struct pnp_option *pnp_register_dependent_option(struct pnp_dev *dev,
include/linux/pnp.h +0 -48

54 lines not on this page · raw message

#9 lore raw

Re: [patch 04/15] PNP: make resource option structures private to PNP subsystem

Quoted 5 lines · Bjorn Helgaas

Nothing outside the PNP subsystem should need access to a device's resource options, so this patch moves the option structure declarations to a private header file.

I guess this is dependent on the 8250_pnp note I sent earlier.

Rene.

#10 lore raw

PATCH 5/15 PNP: introduce pnp_irq_mask_t typedef

In reply to Bjorn Helgaas

This adds a typedef for the IRQ bitmap, which should cause no functional change, but will make it easier to pass a pointer to a bitmap to pnp_register_irq_resource().

drivers/pnp/base.h +3 -1
Index: work10/drivers/pnp/base.h
===================================================================
@@ -30,8 +30,10 @@ struct pnp_port {
 };
 
 #define PNP_IRQ_NR 256
+typedef struct { DECLARE_BITMAP(bits, PNP_IRQ_NR); } pnp_irq_mask_t;
+
 struct pnp_irq {
-	DECLARE_BITMAP(map, PNP_IRQ_NR);	/* bitmask for IRQ lines */
+	pnp_irq_mask_t map;	/* bitmap for IRQ lines */
 	unsigned char flags;	/* IRQ flags */
 	unsigned char pad;	/* pad */
 	struct pnp_irq *next;	/* next IRQ */
drivers/pnp/resource.c +2 -2
Index: work10/drivers/pnp/resource.c
===================================================================
@@ -98,13 +98,13 @@ int pnp_register_irq_resource(struct pnp
 		int i;
 
 		for (i = 0; i < 16; i++)
-			if (test_bit(i, data->map))
+			if (test_bit(i, data->map.bits))
 				pcibios_penalize_isa_irq(i, 0);
 	}
 #endif
 
 #ifdef DEBUG
-	bitmap_scnprintf(buf, sizeof(buf), data->map, PNP_IRQ_NR);
+	bitmap_scnprintf(buf, sizeof(buf), data->map.bits, PNP_IRQ_NR);
 	dev_dbg(&dev->dev, "  irq bitmask %s flags %#x\n", buf,
 		data->flags);
 #endif
drivers/pnp/manager.c +3 -3
Index: work10/drivers/pnp/manager.c
===================================================================
@@ -128,20 +128,20 @@ static int pnp_assign_irq(struct pnp_dev
 	res->start = -1;
 	res->end = -1;
 
-	if (bitmap_empty(rule->map, PNP_IRQ_NR)) {
+	if (bitmap_empty(rule->map.bits, PNP_IRQ_NR)) {
 		res->flags |= IORESOURCE_DISABLED;
 		dev_dbg(&dev->dev, "  irq %d disabled\n", idx);
 		goto __add;
 	}
 
 	/* TBD: need check for >16 IRQ */
-	res->start = find_next_bit(rule->map, PNP_IRQ_NR, 16);
+	res->start = find_next_bit(rule->map.bits, PNP_IRQ_NR, 16);
 	if (res->start < PNP_IRQ_NR) {
 		res->end = res->start;
 		goto __add;
 	}
 	for (i = 0; i < 16; i++) {
-		if (test_bit(xtab[i], rule->map)) {
+		if (test_bit(xtab[i], rule->map.bits)) {
 			res->start = res->end = xtab[i];
 			if (pnp_check_irq(dev, res))
 				goto __add;
drivers/pnp/interface.c +2 -2
Index: work10/drivers/pnp/interface.c
===================================================================
@@ -67,7 +67,7 @@ static void pnp_print_irq(pnp_info_buffe
 
 	pnp_printf(buffer, "%sirq ", space);
 	for (i = 0; i < PNP_IRQ_NR; i++)
-		if (test_bit(i, irq->map)) {
+		if (test_bit(i, irq->map.bits)) {
 			if (!first) {
 				pnp_printf(buffer, ",");
 			} else {
@@ -78,7 +78,7 @@ static void pnp_print_irq(pnp_info_buffe
 			else
 				pnp_printf(buffer, "%i", i);
 		}
-	if (bitmap_empty(irq->map, PNP_IRQ_NR))
+	if (bitmap_empty(irq->map.bits, PNP_IRQ_NR))
 		pnp_printf(buffer, "<none>");
 	if (irq->flags & IORESOURCE_IRQ_HIGHEDGE)
 		pnp_printf(buffer, " High-Edge");
drivers/pnp/isapnp/core.c +1 -1
Index: work10/drivers/pnp/isapnp/core.c
===================================================================
@@ -441,7 +441,7 @@ static void __init isapnp_parse_irq_reso
 	if (!irq)
 		return;
 	bits = (tmp[1] << 8) | tmp[0];
-	bitmap_copy(irq->map, &bits, 16);
+	bitmap_copy(irq->map.bits, &bits, 16);
 	if (size > 2)
 		irq->flags = tmp[2];
 	else
drivers/pnp/pnpacpi/rsparser.c +2 -2
Index: work10/drivers/pnp/pnpacpi/rsparser.c
===================================================================
@@ -408,7 +408,7 @@ static __init void pnpacpi_parse_irq_opt
 
 	for (i = 0; i < p->interrupt_count; i++)
 		if (p->interrupts[i])
-			__set_bit(p->interrupts[i], irq->map);
+			__set_bit(p->interrupts[i], irq->map.bits);
 	irq->flags = irq_flags(p->triggering, p->polarity, p->sharable);
 
 	pnp_register_irq_resource(dev, option, irq);
@@ -429,7 +429,7 @@ static __init void pnpacpi_parse_ext_irq
 
 	for (i = 0; i < p->interrupt_count; i++)
 		if (p->interrupts[i])
-			__set_bit(p->interrupts[i], irq->map);
+			__set_bit(p->interrupts[i], irq->map.bits);
 	irq->flags = irq_flags(p->triggering, p->polarity, p->sharable);
 
 	pnp_register_irq_resource(dev, option, irq);
drivers/pnp/quirks.c +2 -2
Index: work10/drivers/pnp/quirks.c
===================================================================
@@ -68,7 +68,7 @@ static void quirk_cmi8330_resources(stru
 
 		for (irq = res->irq; irq; irq = irq->next) {	// Valid irqs are 5, 7, 10
 			tmp = 0x04A0;
-			bitmap_copy(irq->map, &tmp, 16);	// 0000 0100 1010 0000
+			bitmap_copy(irq->map.bits, &tmp, 16);	// 0000 0100 1010 0000
 		}
 
 		for (dma = res->dma; dma; dma = dma->next)	// Valid 8bit dma channels are 1,3
@@ -187,7 +187,7 @@ static void quirk_ad1815_mpu_resources(s
 		if (!copy)
 			break;
 
-		memcpy(copy->map, irq->map, sizeof copy->map);
+		bitmap_copy(copy->map.bits, irq->map.bits, PNP_IRQ_NR);
 		copy->flags = irq->flags;
 
 		copy->next = res->irq; /* Yes, this is NULL */
drivers/pnp/pnpbios/rsparser.c +1 -1
Index: work10/drivers/pnp/pnpbios/rsparser.c
===================================================================
@@ -275,7 +275,7 @@ static __init void pnpbios_parse_irq_opt
 	if (!irq)
 		return;
 	bits = (p[2] << 8) | p[1];
-	bitmap_copy(irq->map, &bits, 16);
+	bitmap_copy(irq->map.bits, &bits, 16);
 	if (size > 2)
 		irq->flags = p[3];
 	else
#12 lore raw

PATCH 6/15 PNP: increase I/O port & memory option address sizes

In reply to Bjorn Helgaas

ACPI Address Space Descriptors can be up to 64 bits wide. We should keep track of the whole thing when parsing resource options, so this patch changes PNP port and mem option fields from "unsigned short" and "unsigned int" to "resource_size_t".

---
 drivers/pnp/base.h      |   16 ++++++++--------
 drivers/pnp/interface.c |   17 +++++++++++------
 drivers/pnp/resource.c  |   14 ++++++++++----
 3 files changed, 29 insertions(+), 18 deletions(-)
drivers/pnp/base.h +8 -8
Index: work10/drivers/pnp/base.h
===================================================================
@@ -20,10 +20,10 @@ int pnp_add_card_device(struct pnp_card 
 void pnp_remove_card_device(struct pnp_dev *dev);
 
 struct pnp_port {
-	unsigned short min;	/* min base number */
-	unsigned short max;	/* max base number */
-	unsigned char align;	/* align boundary */
-	unsigned char size;	/* size of range */
+	resource_size_t min;	/* min base number */
+	resource_size_t max;	/* max base number */
+	resource_size_t align;	/* align boundary */
+	resource_size_t size;	/* size of range */
 	unsigned char flags;	/* port flags */
 	unsigned char pad;	/* pad */
 	struct pnp_port *next;	/* next port */
@@ -46,10 +46,10 @@ struct pnp_dma {
 };
 
 struct pnp_mem {
-	unsigned int min;	/* min base number */
-	unsigned int max;	/* max base number */
-	unsigned int align;	/* align boundary */
-	unsigned int size;	/* size of range */
+	resource_size_t min;	/* min base number */
+	resource_size_t max;	/* max base number */
+	resource_size_t align;	/* align boundary */
+	resource_size_t size;	/* size of range */
 	unsigned char flags;	/* memory flags */
 	unsigned char pad;	/* pad */
 	struct pnp_mem *next;	/* next memory resource */
drivers/pnp/interface.c +11 -6
Index: work10/drivers/pnp/interface.c
===================================================================
@@ -53,10 +53,12 @@ static int pnp_printf(pnp_info_buffer_t 
 static void pnp_print_port(pnp_info_buffer_t * buffer, char *space,
 			   struct pnp_port *port)
 {
-	pnp_printf(buffer,
-		   "%sport 0x%x-0x%x, align 0x%x, size 0x%x, %i-bit address decoding\n",
-		   space, port->min, port->max,
-		   port->align ? (port->align - 1) : 0, port->size,
+	pnp_printf(buffer, "%sport %#llx-%#llx, align %#llx, size %#llx, "
+		   "%i-bit address decoding\n", space,
+		   (unsigned long long) port->min,
+		   (unsigned long long) port->max,
+		   port->align ? ((unsigned long long) port->align - 1) : 0,
+		   (unsigned long long) port->size,
 		   port->flags & IORESOURCE_IO_16BIT_ADDR ? 16 : 10);
 }
 
@@ -148,8 +150,11 @@ static void pnp_print_mem(pnp_info_buffe
 {
 	char *s;
 
-	pnp_printf(buffer, "%sMemory 0x%x-0x%x, align 0x%x, size 0x%x",
-		   space, mem->min, mem->max, mem->align, mem->size);
+	pnp_printf(buffer, "%sMemory %#llx-%#llx, align %#llx, size %#llx",
+		   space, (unsigned long long) mem->min,
+		   (unsigned long long) mem->max,
+		   (unsigned long long) mem->align,
+		   (unsigned long long) mem->size);
 	if (mem->flags & IORESOURCE_MEM_WRITEABLE)
 		pnp_printf(buffer, ", writeable");
 	if (mem->flags & IORESOURCE_MEM_CACHEABLE)
drivers/pnp/resource.c +10 -4
Index: work10/drivers/pnp/resource.c
===================================================================
@@ -143,8 +143,11 @@ int pnp_register_port_resource(struct pn
 		option->port = data;
 
 	dev_dbg(&dev->dev, "  io  "
-		"min %#x max %#x align %d size %d flags %#x\n",
-		data->min, data->max, data->align, data->size, data->flags);
+		"min %#llx max %#llx align %lld size %lld flags %#x\n",
+		(unsigned long long) data->min,
+		(unsigned long long) data->max,
+		(unsigned long long) data->align,
+		(unsigned long long) data->size, data->flags);
 	return 0;
 }
 
@@ -162,8 +165,11 @@ int pnp_register_mem_resource(struct pnp
 		option->mem = data;
 
 	dev_dbg(&dev->dev, "  mem "
-		"min %#x max %#x align %d size %d flags %#x\n",
-		data->min, data->max, data->align, data->size, data->flags);
+		"min %#llx max %#llx align %lld size %lld flags %#x\n",
+		(unsigned long long) data->min,
+		(unsigned long long) data->max,
+		(unsigned long long) data->align,
+		(unsigned long long) data->size, data->flags);
 	return 0;
 }
 
Acked-by on v1 6/15
#13 lore raw

Re: [patch 06/15] PNP: increase I/O port & memory option address sizes

Quoted 7 lines · Bjorn Helgaas

ACPI Address Space Descriptors can be up to 64 bits wide. We should keep track of the whole thing when parsing resource options, so this patch changes PNP port and mem option fields from "unsigned short" and "unsigned int" to "resource_size_t".

Rene.

#14 lore raw

PATCH 7/15 PNP: improve resource assignment debug

In reply to Bjorn Helgaas

When we fail to assign an I/O or MEM resource, include the min/max in the debug output to help match it with the options.

drivers/pnp/manager.c +8 -2
Index: work10/drivers/pnp/manager.c
===================================================================
@@ -47,7 +47,10 @@ static int pnp_assign_port(struct pnp_de
 		res->start += rule->align;
 		res->end = res->start + rule->size - 1;
 		if (res->start > rule->max || !rule->align) {
-			dev_dbg(&dev->dev, "  couldn't assign io %d\n", idx);
+			dev_dbg(&dev->dev, "  couldn't assign io %d "
+				"(min %#llx max %#llx)\n", idx,
+				(unsigned long long) rule->min,
+				(unsigned long long) rule->max);
 			return 0;
 		}
 	}
@@ -96,7 +99,10 @@ static int pnp_assign_mem(struct pnp_dev
 		res->start += rule->align;
 		res->end = res->start + rule->size - 1;
 		if (res->start > rule->max || !rule->align) {
-			dev_dbg(&dev->dev, "  couldn't assign mem %d\n", idx);
+			dev_dbg(&dev->dev, "  couldn't assign mem %d "
+				"(min %#llx max %#llx)\n", idx,
+				(unsigned long long) rule->min,
+				(unsigned long long) rule->max);
 			return 0;
 		}
 	}
#16 lore raw

PATCH 8/15 PNP: in debug resource dump, make empty list obvious

In reply to Bjorn Helgaas

If the resource list is empty, say that explicitly. Previously, it was confusing because often the heading was followed by zero resource lines, then some "add resource" lines from auto-assignment, so the "add" lines looked like current resources.

drivers/pnp/support.c +6 -1
Index: work10/drivers/pnp/support.c
===================================================================
@@ -77,7 +77,12 @@ void dbg_pnp_show_resources(struct pnp_d
 	struct pnp_resource *pnp_res;
 	struct resource *res;
 
-	dev_dbg(&dev->dev, "current resources: %s\n", desc);
+	if (list_empty(&dev->resources)) {
+		dev_dbg(&dev->dev, "%s: no current resources\n", desc);
+		return;
+	}
+
+	dev_dbg(&dev->dev, "%s: current resources:\n", desc);
 	list_for_each_entry(pnp_res, &dev->resources, list) {
 		res = &pnp_res->res;
 
Acked-by on v1 8/15
#17 lore raw

Re: [patch 08/15] PNP: in debug resource dump, make empty list obvious

Quoted 6 lines · Bjorn Helgaas

If the resource list is empty, say that explicitly. Previously, it was confusing because often the heading was followed by zero resource lines, then some "add resource" lines from auto-assignment, so the "add" lines looked like current resources.

Rene.

#18 lore raw

PATCH 9/15 PNP: make resource assignment functions return 0 (success) or -EBUSY (failure)

In reply to Bjorn Helgaas

This patch doesn't change any behavior; it just makes the return values more conventional.

This changes pnp_assign_dma() from a void function to one that returns an int, just like the other assignment functions. For now, at least, pnp_assign_dma() always returns 0 (success), so it appears to never fail, just like before.

drivers/pnp/manager.c +22 -19
Index: work10/drivers/pnp/manager.c
===================================================================
@@ -26,7 +26,7 @@ static int pnp_assign_port(struct pnp_de
 		dev_dbg(&dev->dev, "  io %d already set to %#llx-%#llx "
 			"flags %#lx\n", idx, (unsigned long long) res->start,
 			(unsigned long long) res->end, res->flags);
-		return 1;
+		return 0;
 	}
 
 	res = &local_res;
@@ -51,13 +51,13 @@ static int pnp_assign_port(struct pnp_de
 				"(min %#llx max %#llx)\n", idx,
 				(unsigned long long) rule->min,
 				(unsigned long long) rule->max);
-			return 0;
+			return -EBUSY;
 		}
 	}
 
 __add:
 	pnp_add_io_resource(dev, res->start, res->end, res->flags);
-	return 1;
+	return 0;
 }
 
 static int pnp_assign_mem(struct pnp_dev *dev, struct pnp_mem *rule, int idx)
@@ -69,7 +69,7 @@ static int pnp_assign_mem(struct pnp_dev
 		dev_dbg(&dev->dev, "  mem %d already set to %#llx-%#llx "
 			"flags %#lx\n", idx, (unsigned long long) res->start,
 			(unsigned long long) res->end, res->flags);
-		return 1;
+		return 0;
 	}
 
 	res = &local_res;
@@ -103,13 +103,13 @@ static int pnp_assign_mem(struct pnp_dev
 				"(min %#llx max %#llx)\n", idx,
 				(unsigned long long) rule->min,
 				(unsigned long long) rule->max);
-			return 0;
+			return -EBUSY;
 		}
 	}
 
 __add:
 	pnp_add_mem_resource(dev, res->start, res->end, res->flags);
-	return 1;
+	return 0;
 }
 
 static int pnp_assign_irq(struct pnp_dev *dev, struct pnp_irq *rule, int idx)
@@ -126,7 +126,7 @@ static int pnp_assign_irq(struct pnp_dev
 	if (res) {
 		dev_dbg(&dev->dev, "  irq %d already set to %d flags %#lx\n",
 			idx, (int) res->start, res->flags);
-		return 1;
+		return 0;
 	}
 
 	res = &local_res;
@@ -154,14 +154,14 @@ static int pnp_assign_irq(struct pnp_dev
 		}
 	}
 	dev_dbg(&dev->dev, "  couldn't assign irq %d\n", idx);
-	return 0;
+	return -EBUSY;
 
 __add:
 	pnp_add_irq_resource(dev, res->start, res->flags);
-	return 1;
+	return 0;
 }
 
-static void pnp_assign_dma(struct pnp_dev *dev, struct pnp_dma *rule, int idx)
+static int pnp_assign_dma(struct pnp_dev *dev, struct pnp_dma *rule, int idx)
 {
 	struct resource *res, local_res;
 	int i;
@@ -175,7 +175,7 @@ static void pnp_assign_dma(struct pnp_de
 	if (res) {
 		dev_dbg(&dev->dev, "  dma %d already set to %d flags %#lx\n",
 			idx, (int) res->start, res->flags);
-		return;
+		return 0;
 	}
 
 	res = &local_res;
@@ -198,6 +198,7 @@ static void pnp_assign_dma(struct pnp_de
 
 __add:
 	pnp_add_dma_resource(dev, res->start, res->flags);
+	return 0;
 }
 
 void pnp_init_resources(struct pnp_dev *dev)
@@ -243,25 +244,26 @@ static int pnp_assign_resources(struct p
 		irq = dev->independent->irq;
 		dma = dev->independent->dma;
 		while (port) {
-			if (!pnp_assign_port(dev, port, nport))
+			if (pnp_assign_port(dev, port, nport) < 0)
 				goto fail;
 			nport++;
 			port = port->next;
 		}
 		while (mem) {
-			if (!pnp_assign_mem(dev, mem, nmem))
+			if (pnp_assign_mem(dev, mem, nmem) < 0)
 				goto fail;
 			nmem++;
 			mem = mem->next;
 		}
 		while (irq) {
-			if (!pnp_assign_irq(dev, irq, nirq))
+			if (pnp_assign_irq(dev, irq, nirq) < 0)
 				goto fail;
 			nirq++;
 			irq = irq->next;
 		}
 		while (dma) {
-			pnp_assign_dma(dev, dma, ndma);
+			if (pnp_assign_dma(dev, dma, ndma) < 0)
+				goto fail;
 			ndma++;
 			dma = dma->next;
 		}
@@ -281,25 +283,26 @@ static int pnp_assign_resources(struct p
 		irq = dep->irq;
 		dma = dep->dma;
 		while (port) {
-			if (!pnp_assign_port(dev, port, nport))
+			if (pnp_assign_port(dev, port, nport) < 0)
 				goto fail;
 			nport++;
 			port = port->next;
 		}
 		while (mem) {
-			if (!pnp_assign_mem(dev, mem, nmem))
+			if (pnp_assign_mem(dev, mem, nmem) < 0)
 				goto fail;
 			nmem++;
 			mem = mem->next;
 		}
 		while (irq) {
-			if (!pnp_assign_irq(dev, irq, nirq))
+			if (pnp_assign_irq(dev, irq, nirq) < 0)
 				goto fail;
 			nirq++;
 			irq = irq->next;
 		}
 		while (dma) {
-			pnp_assign_dma(dev, dma, ndma);
+			if (pnp_assign_dma(dev, dma, ndma) < 0)
+				goto fail;
 			ndma++;
 			dma = dma->next;
 		}
Acked-by on v1 9/15
#19 lore raw

Re: [patch 09/15] PNP: make resource assignment functions return 0 (success) or -EBUSY (failure)

Quoted 9 lines · Bjorn Helgaas

This patch doesn't change any behavior; it just makes the return values more conventional.

This changes pnp_assign_dma() from a void function to one that returns an int, just like the other assignment functions. For now, at least, pnp_assign_dma() always returns 0 (success), so it appears to never fail, just like before.

I believe it would a bit nicer to (as long as we're pretending it matters in the first place) pass the return value back up from pnp_check_foo() instead of returning -EBUSY always but <shrug>

Rene.

#20 lore raw

PATCH 10/15 PNP: remove redundant pnp_can_configure() check

In reply to Bjorn Helgaas

pnp_assign_resources() is static and the only caller checks pnp_can_configure() before calling it, so no need to do it again.

drivers/pnp/manager.c +0 -3
Index: work10/drivers/pnp/manager.c
===================================================================
@@ -231,9 +231,6 @@ static int pnp_assign_resources(struct p
 	struct pnp_dma *dma;
 	int nport = 0, nmem = 0, nirq = 0, ndma = 0;
 
-	if (!pnp_can_configure(dev))
-		return -ENODEV;
-
 	dbg_pnp_show_resources(dev, "before pnp_assign_resources");
 	mutex_lock(&pnp_res_mutex);
 	pnp_clean_resource_table(dev);
#22 lore raw

PATCH 11/15 PNP: centralize resource option allocations

In reply to Bjorn Helgaas

This patch moves all the option allocations (pnp_mem, pnp_port, etc) into the pnp_register_{mem,port,irq,dma}_resource() functions. This will make it easier to rework the option data structures.

The non-trivial part of this patch is the IRQ handling. The backends have to allocate a local pnp_irq_mask_t bitmap, populate it, and pass a pointer to pnp_register_irq_resource().

---
 drivers/pnp/base.h             |   12 ++-
 drivers/pnp/isapnp/core.c      |  115 +++++++++++++------------------
 drivers/pnp/pnpacpi/rsparser.c |  149 +++++++++++++----------------------------
 drivers/pnp/pnpbios/rsparser.c |  112 ++++++++++++------------------
 drivers/pnp/resource.c         |   58 +++++++++++++--
 5 files changed, 200 insertions(+), 246 deletions(-)
drivers/pnp/base.h +8 -4
Index: work10/drivers/pnp/base.h
===================================================================
@@ -74,13 +74,17 @@ struct pnp_option *pnp_register_independ
 struct pnp_option *pnp_register_dependent_option(struct pnp_dev *dev,
 						 int priority);
 int pnp_register_irq_resource(struct pnp_dev *dev, struct pnp_option *option,
-			      struct pnp_irq *data);
+			      pnp_irq_mask_t *map, unsigned char flags);
 int pnp_register_dma_resource(struct pnp_dev *dev, struct pnp_option *option,
-			      struct pnp_dma *data);
+			      unsigned char map, unsigned char flags);
 int pnp_register_port_resource(struct pnp_dev *dev, struct pnp_option *option,
-			       struct pnp_port *data);
+			       resource_size_t min, resource_size_t max,
+			       resource_size_t align, resource_size_t size,
+			       unsigned char flags);
 int pnp_register_mem_resource(struct pnp_dev *dev, struct pnp_option *option,
-			      struct pnp_mem *data);
+			      resource_size_t min, resource_size_t max,
+			      resource_size_t align, resource_size_t size,
+			      unsigned char flags);
 void pnp_init_resources(struct pnp_dev *dev);
 
 void pnp_fixup_device(struct pnp_dev *dev);
drivers/pnp/isapnp/core.c +48 -67

174 lines not on this page · raw message

drivers/pnp/pnpacpi/rsparser.c +49 -100

246 lines not on this page · raw message

drivers/pnp/pnpbios/rsparser.c +47 -65

163 lines not on this page · raw message

drivers/pnp/resource.c +48 -10

88 lines not on this page · raw message

Acked-by on v1 11/15
#23 lore raw

Re: [patch 11/15] PNP: centralize resource option allocations

Quoted 9 lines · Bjorn Helgaas

This patch moves all the option allocations (pnp_mem, pnp_port, etc) into the pnp_register_{mem,port,irq,dma}_resource() functions. This will make it easier to rework the option data structures.

The non-trivial part of this patch is the IRQ handling. The backends have to allocate a local pnp_irq_mask_t bitmap, populate it, and pass a pointer to pnp_register_irq_resource().

[ ... ]

Quoted 16 lines

Index: work10/drivers/pnp/isapnp/core.c
===================================================================

drivers/pnp/isapnp/core.c +3 -2
@@ -433,20 +433,23 @@ static void __init isapnp_parse_irq_reso
 					     int size)
 {
 	unsigned char tmp[3];
-	struct pnp_irq *irq;
 	unsigned long bits;
+	int i;
+	pnp_irq_mask_t map;
+	unsigned char flags = IORESOURCE_IRQ_HIGHEDGE;
 
 	isapnp_peek(tmp, size);
-	irq = kzalloc(sizeof(struct pnp_irq), GFP_KERNEL);

drivers/pnp/isapnp/core.c static void __init isapnp_parse_irq_reso · line 448

Quoted 10 lines
drivers/pnp/isapnp/core.c +6 -3
-	if (!irq)
-		return;
 	bits = (tmp[1] << 8) | tmp[0];
-	bitmap_copy(irq->map.bits, &bits, 16);
+
+	bitmap_zero(map.bits, PNP_IRQ_NR);
+	for (i = 0; i < 15; i++)
+		if (bits & (1 << i))
+			__set_bit(i, map.bits);
+

for (i = 0; i < 16; i++) (16 instead of 15) it would seem.

And why not simply:

bitmap_zero(map.bits, PNP_IRQ_NR);
bitmap_copy(map.bits, &bits, 16);

That last bit of the comment same for pnpbios_parse_irq_option(). Should
be fine, no?

drivers/pnp/isapnp/core.c static void __init isapnp_parse_irq_reso · line 453

Quoted 6 lines
drivers/pnp/isapnp/core.c +1 -1
 static __init void pnpbios_parse_port_option(struct pnp_dev *dev,
 					     unsigned char *p, int size,
 					     struct pnp_option *option)
 {
-	struct pnp_port *port;
+	resource_size_t min, max, align, len, flags;

unsigned char flags;

All the rest:

Rene.

#24 lore raw

Re: [patch 11/15] PNP: centralize resource option allocations

Quoted 28 lines · Rene Herman
Quoted 9 lines · Bjorn Helgaas

This patch moves all the option allocations (pnp_mem, pnp_port, etc) into the pnp_register_{mem,port,irq,dma}_resource() functions. This will make it easier to rework the option data structures.

The non-trivial part of this patch is the IRQ handling. The backends have to allocate a local pnp_irq_mask_t bitmap, populate it, and pass a pointer to pnp_register_irq_resource().

[ ... ]

Quoted 14 lines

Index: work10/drivers/pnp/isapnp/core.c
===================================================================

drivers/pnp/isapnp/core.c +3 -1
@@ -433,20 +433,23 @@ static void __init isapnp_parse_irq_reso
 					     int size)
 {
 	unsigned char tmp[3];
-	struct pnp_irq *irq;
 	unsigned long bits;
+	int i;
+	pnp_irq_mask_t map;
+	unsigned char flags = IORESOURCE_IRQ_HIGHEDGE;
 
Quoted 14 lines

drivers/pnp/isapnp/core.c static void __init isapnp_parse_irq_reso · line 448

Quoted 12 lines
drivers/pnp/isapnp/core.c +6 -4
 	isapnp_peek(tmp, size);
-	irq = kzalloc(sizeof(struct pnp_irq), GFP_KERNEL);
-	if (!irq)
-		return;
 	bits = (tmp[1] << 8) | tmp[0];
-	bitmap_copy(irq->map.bits, &bits, 16);
+
+	bitmap_zero(map.bits, PNP_IRQ_NR);
+	for (i = 0; i < 15; i++)
+		if (bits & (1 << i))
+			__set_bit(i, map.bits);
+

for (i = 0; i < 16; i++) (16 instead of 15) it would seem.

Oops, typo on my part.

Quoted 7 lines

And why not simply:

bitmap_zero(map.bits, PNP_IRQ_NR);
bitmap_copy(map.bits, &bits, 16);

That last bit of the comment same for pnpbios_parse_irq_option(). Should
be fine, no?

I suppose it should be fine. It's just that I was new to the bitmap functions and nervous about copying between bitmaps of different sizes and getting bits in the correct places. But I'll try to get over my paranoia :-)

Bjorn

#25 lore raw

PATCH 12/15 PNPACPI: ignore _PRS interrupt numbers larger than PNP_IRQ_NR

In reply to Bjorn Helgaas

ACPI Extended Interrupt Descriptors can encode 32-bit interrupt numbers, so an interrupt number may exceed the size of the bitmap we use to track possible IRQ settings.

To avoid corrupting memory, complain and ignore too-large interrupt numbers.

There's similar code in pnpacpi_parse_irq_option(), but I didn't change that because the small IRQ descriptor can only encode IRQs 0-15, which do not exceed bitmap size.

In the future, we could handle IRQ numbers greater than PNP_IRQ_NR by replacing the bitmap with a table or list.

drivers/pnp/pnpacpi/rsparser.c +10 -3
Index: work10/drivers/pnp/pnpacpi/rsparser.c
===================================================================
@@ -421,9 +421,16 @@ static __init void pnpacpi_parse_ext_irq
 		return;
 
 	bitmap_zero(map.bits, PNP_IRQ_NR);
-	for (i = 0; i < p->interrupt_count; i++)
-		if (p->interrupts[i])
-			__set_bit(p->interrupts[i], map.bits);
+	for (i = 0; i < p->interrupt_count; i++) {
+		if (p->interrupts[i]) {
+			if (p->interrupts[i] < PNP_IRQ_NR)
+				__set_bit(p->interrupts[i], map.bits);
+			else
+				dev_err(&dev->dev, "ignoring IRQ %d option "
+					"(too large for %d entry bitmap)\n",
+					p->interrupts[i], PNP_IRQ_NR);
+		}
+	}
 
 	flags = irq_flags(p->triggering, p->polarity, p->sharable);
 	pnp_register_irq_resource(dev, option, &map, flags);
Acked-by on v1 12/15
#26 lore raw

Re: [patch 12/15] PNPACPI: ignore _PRS interrupt numbers larger than PNP_IRQ_NR

Quoted 7 lines · Bjorn Helgaas

ACPI Extended Interrupt Descriptors can encode 32-bit interrupt numbers, so an interrupt number may exceed the size of the bitmap we use to track possible IRQ settings.

To avoid corrupting memory, complain and ignore too-large interrupt numbers.

Quoted 8 lines

There's similar code in pnpacpi_parse_irq_option(), but I didn't change that because the small IRQ descriptor can only encode IRQs 0-15, which do not exceed bitmap size.

In the future, we could handle IRQ numbers greater than PNP_IRQ_NR by replacing the bitmap with a table or list.

Rene.

#27 lore raw

PATCH 13/15 PNP: rename pnp_register_*_resource() local variables

In reply to Bjorn Helgaas

No functional change; just rename "data" to something more descriptive.

drivers/pnp/resource.c +47 -47
Index: work10/drivers/pnp/resource.c
===================================================================
@@ -80,40 +80,40 @@ struct pnp_option *pnp_register_dependen
 int pnp_register_irq_resource(struct pnp_dev *dev, struct pnp_option *option,
 			      pnp_irq_mask_t *map, unsigned char flags)
 {
-	struct pnp_irq *data, *ptr;
+	struct pnp_irq *irq, *ptr;
 #ifdef DEBUG
 	char buf[PNP_IRQ_NR];   /* hex-encoded, so this is overkill but safe */
 #endif
 
-	data = kzalloc(sizeof(struct pnp_irq), GFP_KERNEL);
-	if (!data)
+	irq = kzalloc(sizeof(struct pnp_irq), GFP_KERNEL);
+	if (!irq)
 		return -ENOMEM;
 
-	data->map = *map;
-	data->flags = flags;
+	irq->map = *map;
+	irq->flags = flags;
 
 	ptr = option->irq;
 	while (ptr && ptr->next)
 		ptr = ptr->next;
 	if (ptr)
-		ptr->next = data;
+		ptr->next = irq;
 	else
-		option->irq = data;
+		option->irq = irq;
 
 #ifdef CONFIG_PCI
 	{
 		int i;
 
 		for (i = 0; i < 16; i++)
-			if (test_bit(i, data->map.bits))
+			if (test_bit(i, irq->map.bits))
 				pcibios_penalize_isa_irq(i, 0);
 	}
 #endif
 
 #ifdef DEBUG
-	bitmap_scnprintf(buf, sizeof(buf), data->map.bits, PNP_IRQ_NR);
+	bitmap_scnprintf(buf, sizeof(buf), irq->map.bits, PNP_IRQ_NR);
 	dev_dbg(&dev->dev, "  irq bitmask %s flags %#x\n", buf,
-		data->flags);
+		irq->flags);
 #endif
 	return 0;
 }
@@ -121,25 +121,25 @@ int pnp_register_irq_resource(struct pnp
 int pnp_register_dma_resource(struct pnp_dev *dev, struct pnp_option *option,
 			      unsigned char map, unsigned char flags)
 {
-	struct pnp_dma *data, *ptr;
+	struct pnp_dma *dma, *ptr;
 
-	data = kzalloc(sizeof(struct pnp_dma), GFP_KERNEL);
-	if (!data)
+	dma = kzalloc(sizeof(struct pnp_dma), GFP_KERNEL);
+	if (!dma)
 		return -ENOMEM;
 
-	data->map = map;
-	data->flags = flags;
+	dma->map = map;
+	dma->flags = flags;
 
 	ptr = option->dma;
 	while (ptr && ptr->next)
 		ptr = ptr->next;
 	if (ptr)
-		ptr->next = data;
+		ptr->next = dma;
 	else
-		option->dma = data;
+		option->dma = dma;
 
-	dev_dbg(&dev->dev, "  dma bitmask %#x flags %#x\n", data->map,
-		data->flags);
+	dev_dbg(&dev->dev, "  dma bitmask %#x flags %#x\n", dma->map,
+		dma->flags);
 	return 0;
 }
 
@@ -148,32 +148,32 @@ int pnp_register_port_resource(struct pn
 			       resource_size_t align, resource_size_t size,
 			       unsigned char flags)
 {
-	struct pnp_port *data, *ptr;
+	struct pnp_port *port, *ptr;
 
-	data = kzalloc(sizeof(struct pnp_port), GFP_KERNEL);
-	if (!data)
+	port = kzalloc(sizeof(struct pnp_port), GFP_KERNEL);
+	if (!port)
 		return -ENOMEM;
 
-	data->min = min;
-	data->max = max;
-	data->align = align;
-	data->size = size;
-	data->flags = flags;
+	port->min = min;
+	port->max = max;
+	port->align = align;
+	port->size = size;
+	port->flags = flags;
 
 	ptr = option->port;
 	while (ptr && ptr->next)
 		ptr = ptr->next;
 	if (ptr)
-		ptr->next = data;
+		ptr->next = port;
 	else
-		option->port = data;
+		option->port = port;
 
 	dev_dbg(&dev->dev, "  io  "
 		"min %#llx max %#llx align %lld size %lld flags %#x\n",
-		(unsigned long long) data->min,
-		(unsigned long long) data->max,
-		(unsigned long long) data->align,
-		(unsigned long long) data->size, data->flags);
+		(unsigned long long) port->min,
+		(unsigned long long) port->max,
+		(unsigned long long) port->align,
+		(unsigned long long) port->size, port->flags);
 	return 0;
 }
 
@@ -182,32 +182,32 @@ int pnp_register_mem_resource(struct pnp
 			      resource_size_t align, resource_size_t size,
 			      unsigned char flags)
 {
-	struct pnp_mem *data, *ptr;
+	struct pnp_mem *mem, *ptr;
 
-	data = kzalloc(sizeof(struct pnp_mem), GFP_KERNEL);
-	if (!data)
+	mem = kzalloc(sizeof(struct pnp_mem), GFP_KERNEL);
+	if (!mem)
 		return -ENOMEM;
 
-	data->min = min;
-	data->max = max;
-	data->align = align;
-	data->size = size;
-	data->flags = flags;
+	mem->min = min;
+	mem->max = max;
+	mem->align = align;
+	mem->size = size;
+	mem->flags = flags;
 
 	ptr = option->mem;
 	while (ptr && ptr->next)
 		ptr = ptr->next;
 	if (ptr)
-		ptr->next = data;
+		ptr->next = mem;
 	else
-		option->mem = data;
+		option->mem = mem;
 
 	dev_dbg(&dev->dev, "  mem "
 		"min %#llx max %#llx align %lld size %lld flags %#x\n",
-		(unsigned long long) data->min,
-		(unsigned long long) data->max,
-		(unsigned long long) data->align,
-		(unsigned long long) data->size, data->flags);
+		(unsigned long long) mem->min,
+		(unsigned long long) mem->max,
+		(unsigned long long) mem->align,
+		(unsigned long long) mem->size, mem->flags);
 	return 0;
 }
 
#29 lore raw

PATCH 14/15 PNP: support optional IRQ resources

In reply to Bjorn Helgaas

This patch adds an IORESOURCE_IRQ_OPTIONAL flag for use when assigning resources to a device. If the flag is set and we are unable to assign an IRQ to the device, we can leave the IRQ disabled but allow the overall resource allocation to succeed.

Some devices request an IRQ, but can run without an IRQ (possibly with degraded performance). This flag lets us run the device without the IRQ instead of just leaving the device disabled.

This is a reimplementation of this previous change by Rene Herman <[email protected]>:

    http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=3b73a223661ed137c5d3d2635f954382e94f5a43

I reimplemented this for two reasons:
- to prepare for converting all resource options into a single linked list, as opposed to the per-resource-type lists we have now, and
- to preserve the order and number of resource options.

In PNPBIOS and ACPI, we configure a device by giving firmware a list of resource assignments. It is important that this list has exactly the same number of resources, in the same order, as the "template" list we got from the firmware in the first place.

The problem of a sound card being left disabled for want of an IRQ was reported by Uwe Bugla <[email protected]>.

include/linux/ioport.h +1 -0
Index: work10/include/linux/ioport.h
===================================================================
@@ -59,6 +59,7 @@ struct resource_list {
 #define IORESOURCE_IRQ_HIGHLEVEL	(1<<2)
 #define IORESOURCE_IRQ_LOWLEVEL		(1<<3)
 #define IORESOURCE_IRQ_SHAREABLE	(1<<4)
+#define IORESOURCE_IRQ_OPTIONAL		(1<<5)
 
 /* ISA PnP DMA specific bits (IORESOURCE_BITS) */
 #define IORESOURCE_DMA_TYPE_MASK	(3<<0)
drivers/pnp/manager.c +9 -0
Index: work10/drivers/pnp/manager.c
===================================================================
@@ -153,6 +153,15 @@ static int pnp_assign_irq(struct pnp_dev
 				goto __add;
 		}
 	}
+
+	if (rule->flags & IORESOURCE_IRQ_OPTIONAL) {
+		res->start = -1;
+		res->end = -1;
+		res->flags |= IORESOURCE_DISABLED;
+		dev_dbg(&dev->dev, "  irq %d disabled (optional)\n", idx);
+		goto __add;
+	}
+
 	dev_dbg(&dev->dev, "  couldn't assign irq %d\n", idx);
 	return -EBUSY;
 
drivers/pnp/quirks.c +27 -42

111 lines not on this page · raw message

#30 lore raw

Re: [patch 14/15] PNP: support optional IRQ resources

Quoted 19 lines · Bjorn Helgaas

This patch adds an IORESOURCE_IRQ_OPTIONAL flag for use when assigning resources to a device. If the flag is set and we are unable to assign an IRQ to the device, we can leave the IRQ disabled but allow the overall resource allocation to succeed.

Some devices request an IRQ, but can run without an IRQ (possibly with degraded performance). This flag lets us run the device without the IRQ instead of just leaving the device disabled.

This is a reimplementation of this previous change by Rene Herman <[email protected]>:

    http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=3b73a223661ed137c5d3d2635f954382e94f5a43

I reimplemented this for two reasons:
- to prepare for converting all resource options into a single linked list, as opposed to the per-resource-type lists we have now, and
- to preserve the order and number of resource options.

Quoted 8 lines

In PNPBIOS and ACPI, we configure a device by giving firmware a list of resource assignments. It is important that this list has exactly the same number of resources, in the same order, as the "template" list we got from the firmware in the first place.

The problem of a sound card being left disabled for want of an IRQ was reported by Uwe Bugla <[email protected]>.

Nit -- the soundcard itself isn't left disabled, just its MPU401. It's only the fact that ALSA mentions this fact which triggered the report.

Quoted 7 lines

Index: work10/include/linux/ioport.h
===================================================================

include/linux/ioport.h struct resource_list { · line 65

Quoted 7 lines
include/linux/ioport.h +1 -0
@@ -59,6 +59,7 @@ struct resource_list {
 #define IORESOURCE_IRQ_HIGHLEVEL	(1<<2)
 #define IORESOURCE_IRQ_LOWLEVEL		(1<<3)
 #define IORESOURCE_IRQ_SHAREABLE	(1<<4)
+#define IORESOURCE_IRQ_OPTIONAL		(1<<5)
 
 /* ISA PnP DMA specific bits (IORESOURCE_BITS) */
 #define IORESOURCE_DMA_TYPE_MASK	(3<<0)

Andrew scooped up a patch from a previous reaction of mine that deleted the "ISA " from these comments. I tend to use comments as a great way of avoiding actually reading code (I'm silly like that) and so as to be burned a _bit_ less by it, I think it's good if they're accurate. In this case for example, one might be tempted to assume these bits were specific to drivers/pnp/isapnp.

<snip>

Quoted 31 lines
include/linux/ioport.h +0 -20
@@ -164,10 +176,6 @@ static void quirk_ad1815_mpu_resources(s
 	struct pnp_option *res;
 	struct pnp_irq *irq;
 
-	/*
-	 * Distribute the independent IRQ over the dependent options
-	 */
-
 	res = dev->independent;
 	if (!res)
 		return;
@@ -176,33 +184,10 @@ static void quirk_ad1815_mpu_resources(s
 	if (!irq || irq->next)
 		return;
 
-	res = dev->dependent;
-	if (!res)
-		return;
-
-	while (1) {
-		struct pnp_irq *copy;
-
-		copy = pnp_alloc(sizeof *copy);
-		if (!copy)
-			break;
-
-		bitmap_copy(copy->map.bits, irq->map.bits, PNP_IRQ_NR);
-		copy->flags = irq->flags;
-
-		copy->next = res->irq; /* Yes, this is NULL */
-		res->irq = copy;

include/linux/ioport.h static void quirk_ad1815_mpu_resources(s · line 190

Quoted 10 lines
include/linux/ioport.h +2 -6
-
-		if (!res->next)
-			break;
-		res = res->next;
-	}
-	kfree(irq);
+	irq->flags |= IORESOURCE_IRQ_OPTIONAL;
+	dev_info(&dev->dev, "made independent IRQ optional\n");
 
 	res->next = quirk_isapnp_mpu_options(dev);

As commented yesterday, this line should just go. We don't need to clone here (we do for the other two PNP IDs, so the cloning can't go entirely).

The actual (slight) problem with it not working is in 15/15...

include/linux/ioport.h static void quirk_ad1815_mpu_resources(s · line 193

Quoted 6 lines
include/linux/ioport.h +0 -3
-
-	res = dev->independent;
-	res->irq = NULL;
 }
 
 static void quirk_isapnp_mpu_resources(struct pnp_dev *dev)

Rene.

#31 lore raw

Re: [patch 14/15] PNP: support optional IRQ resources

Quoted 10 lines · Rene Herman
Quoted 10 lines

Index: work10/include/linux/ioport.h
===================================================================

include/linux/ioport.h +1 -0
@@ -59,6 +59,7 @@ struct resource_list {
 #define IORESOURCE_IRQ_HIGHLEVEL	(1<<2)
 #define IORESOURCE_IRQ_LOWLEVEL		(1<<3)
 #define IORESOURCE_IRQ_SHAREABLE	(1<<4)
+#define IORESOURCE_IRQ_OPTIONAL		(1<<5)
 
Quoted 9 lines

include/linux/ioport.h struct resource_list { · line 65

Quoted 2 lines
include/linux/ioport.h +0 -0
 /* ISA PnP DMA specific bits (IORESOURCE_BITS) */
 #define IORESOURCE_DMA_TYPE_MASK	(3<<0)

Andrew scooped up a patch from a previous reaction of mine that deleted the "ISA " from these comments. I tend to use comments as a great way of avoiding actually reading code (I'm silly like that) and so as to be burned a _bit_ less by it, I think it's good if they're accurate. In this case for example, one might be tempted to assume these bits were specific to drivers/pnp/isapnp.

Yes, I see that's pnpacpi-fix-irq-flag-decoding-comment-fix.patch in mmotm. How about if I incorporate that in my series (the one Andrew hasn't yet picked up), since your patch will otherwise conflict with it?

Bjorn

#32 lore raw

Re: [patch 14/15] PNP: support optional IRQ resources

Quoted 11 lines · Bjorn Helgaas
Quoted 10 lines · Rene Herman
Quoted 10 lines

Index: work10/include/linux/ioport.h
===================================================================

include/linux/ioport.h +1 -0
@@ -59,6 +59,7 @@ struct resource_list {
 #define IORESOURCE_IRQ_HIGHLEVEL	(1<<2)
 #define IORESOURCE_IRQ_LOWLEVEL		(1<<3)
 #define IORESOURCE_IRQ_SHAREABLE	(1<<4)
+#define IORESOURCE_IRQ_OPTIONAL		(1<<5)
 
Quoted 8 lines
Quoted 3 lines

include/linux/ioport.h struct resource_list { · line 65

Quoted 2 lines
include/linux/ioport.h +0 -0
 /* ISA PnP DMA specific bits (IORESOURCE_BITS) */
 #define IORESOURCE_DMA_TYPE_MASK	(3<<0)

Andrew scooped up a patch from a previous reaction of mine that deleted the "ISA " from these comments. I tend to use comments as a great way of avoiding actually reading code (I'm silly like that) and so as to be burned a _bit_ less by it, I think it's good if they're accurate. In this case for example, one might be tempted to assume these bits were specific to drivers/pnp/isapnp.

Yes, I see that's pnpacpi-fix-irq-flag-decoding-comment-fix.patch in mmotm. How about if I incorporate that in my series (the one Andrew hasn't yet picked up), since your patch will otherwise conflict with it?

Yep, that would be good.

Rene.

#33 lore raw

PATCH 15/15 PNP: convert resource options to single linked list

In reply to Bjorn Helgaas

ISAPNP, PNPBIOS, and ACPI describe the "possible resource settings" of a device, i.e., the possibilities an OS bus driver has when it assigns I/O port, MMIO, and other resources to the device.

PNP used to maintain this "possible resource setting" information in one independent option structure and a list of dependent option structures for each device. Each of these option structures had lists of I/O, memory, IRQ, and DMA resources, for example:

dev

    independent options
      ind-io0  -> ind-io1  ...
      ind-mem0 -> ind-mem1 ...
      ...
    dependent option set 0
      dep0-io0  -> dep0-io1  ...
      dep0-mem0 -> dep0-mem1 ...
      ...
    dependent option set 1
      dep1-io0  -> dep1-io1  ...
      dep1-mem0 -> dep1-mem1 ...
      ...
    ...

This data structure was designed for ISAPNP, where the OS configures device resource settings by writing directly to configuration registers. The OS can write the registers in arbitrary order much like it writes PCI BARs.

However, for PNPBIOS and ACPI devices, the OS uses firmware interfaces that perform device configuration, and it is important to pass the desired settings to those interfaces in the correct order. The OS learns the correct order by using firmware interfaces that return the "current resource settings" and "possible resource settings," but the option structures above doesn't store the ordering information.

This patch replaces the independent and dependent lists with a single list of options. For example, a device might have possible resource settings like this:

dev

    options
      ind-io0 -> dep0-io0 -> dep1->io0 -> ind-io1 ...

All the possible settings are in the same list, in the order they come from the firmware "possible resource settings" list. Each entry is tagged with an independent/dependent flag. Dependent entries also have a "set number" and an optional priority value. All dependent entries must be assigned from the same set. For example, the OS can use all the entries from dependent set 0, or all the entries from dependent set 1, but it cannot use some entries from set 0 and some from set 1.

Prior to this patch PNP didn't keep track of the order of this list, and it assigned all independent options first, then all dependent ones. Using the example above, that resulted in a "desired configuration" list like this:

ind->io0 -> ind->io1 -> depN-io0 ...

instead of the list the firmware expects, which looks like this:

ind->io0 -> depN-io0 -> ind-io1 ...

This reordering results in problems like the one I tried unsuccessfully to fix here:

    http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commitdiff;h=41a5311465b9de6d18e78b733a2c6e1b33e89be8
---
 drivers/pnp/base.h             |   89 +++++++++---
 drivers/pnp/core.c             |    4 
 drivers/pnp/interface.c        |   75 ++++------
 drivers/pnp/isapnp/core.c      |   68 ++++-----
 drivers/pnp/manager.c          |  137 +++++--------------
 drivers/pnp/pnpacpi/rsparser.c |   93 +++++--------
 drivers/pnp/pnpbios/rsparser.c |   64 ++++-----
 drivers/pnp/quirks.c           |  288 ++++++++++++++++++++++-------------------
 drivers/pnp/resource.c         |  205 +++++------------------------
 drivers/pnp/support.c          |   79 +++++++++++
 include/linux/pnp.h            |    6 
 11 files changed, 524 insertions(+), 584 deletions(-)
drivers/pnp/base.h +67 -22
Index: work10/drivers/pnp/base.h
===================================================================
@@ -1,3 +1,8 @@
+/*
+ * (c) Copyright 2008 Hewlett-Packard Development Company, L.P.
+ *	Bjorn Helgaas <[email protected]>
+ */
+
 extern spinlock_t pnp_lock;
 void *pnp_alloc(long size);
 
@@ -25,8 +30,6 @@ struct pnp_port {
 	resource_size_t align;	/* align boundary */
 	resource_size_t size;	/* size of range */
 	unsigned char flags;	/* port flags */
-	unsigned char pad;	/* pad */
-	struct pnp_port *next;	/* next port */
 };
 
 #define PNP_IRQ_NR 256
@@ -35,14 +38,11 @@ typedef struct { DECLARE_BITMAP(bits, PN
 struct pnp_irq {
 	pnp_irq_mask_t map;	/* bitmap for IRQ lines */
 	unsigned char flags;	/* IRQ flags */
-	unsigned char pad;	/* pad */
-	struct pnp_irq *next;	/* next IRQ */
 };
 
 struct pnp_dma {
 	unsigned char map;	/* bitmask for DMA channels */
 	unsigned char flags;	/* DMA flags */
-	struct pnp_dma *next;	/* next port */
 };
 
 struct pnp_mem {
@@ -51,8 +51,6 @@ struct pnp_mem {
 	resource_size_t align;	/* align boundary */
 	resource_size_t size;	/* size of range */
 	unsigned char flags;	/* memory flags */
-	unsigned char pad;	/* pad */
-	struct pnp_mem *next;	/* next memory resource */
 };
 
 #define PNP_RES_PRIORITY_PREFERRED	0
@@ -60,35 +58,82 @@ struct pnp_mem {
 #define PNP_RES_PRIORITY_FUNCTIONAL	2
 #define PNP_RES_PRIORITY_INVALID	65535
 
+#define PNP_OPTION_DEPENDENT		0x80000000
+#define PNP_OPTION_SET_MASK		0xff
+#define PNP_OPTION_SET_SHIFT		16
+#define PNP_OPTION_PRIORITY_MASK	0xffff
+#define PNP_OPTION_PRIORITY_SHIFT	0
+
 struct pnp_option {
-	unsigned short priority;	/* priority */
-	struct pnp_port *port;		/* first port */
-	struct pnp_irq *irq;		/* first IRQ */
-	struct pnp_dma *dma;		/* first DMA */
-	struct pnp_mem *mem;		/* first memory resource */
-	struct pnp_option *next;	/* used to chain dependent resources */
+	struct list_head list;
+	unsigned int flags;	/* independent/dependent, set, priority */
+
+	unsigned long type;	/* IORESOURCE_{IO,MEM,IRQ,DMA} */
+	union {
+		struct pnp_port port;
+		struct pnp_irq irq;
+		struct pnp_dma dma;
+		struct pnp_mem mem;
+	} u;
 };
 
-struct pnp_option *pnp_build_option(int priority);
-struct pnp_option *pnp_register_independent_option(struct pnp_dev *dev);
-struct pnp_option *pnp_register_dependent_option(struct pnp_dev *dev,
-						 int priority);
-int pnp_register_irq_resource(struct pnp_dev *dev, struct pnp_option *option,
+int pnp_register_irq_resource(struct pnp_dev *dev, unsigned int option_flags,
 			      pnp_irq_mask_t *map, unsigned char flags);
-int pnp_register_dma_resource(struct pnp_dev *dev, struct pnp_option *option,
+int pnp_register_dma_resource(struct pnp_dev *dev, unsigned int option_flags,
 			      unsigned char map, unsigned char flags);
-int pnp_register_port_resource(struct pnp_dev *dev, struct pnp_option *option,
+int pnp_register_port_resource(struct pnp_dev *dev, unsigned int option_flags,
 			       resource_size_t min, resource_size_t max,
 			       resource_size_t align, resource_size_t size,
 			       unsigned char flags);
-int pnp_register_mem_resource(struct pnp_dev *dev, struct pnp_option *option,
+int pnp_register_mem_resource(struct pnp_dev *dev, unsigned int option_flags,
 			      resource_size_t min, resource_size_t max,
 			      resource_size_t align, resource_size_t size,
 			      unsigned char flags);
+
+static inline int pnp_option_is_dependent(struct pnp_option *option)
+{
+	return option->flags & PNP_OPTION_DEPENDENT ? 1 : 0;
+}
+
+static inline unsigned int pnp_option_set(struct pnp_option *option)
+{
+	return (option->flags >> PNP_OPTION_SET_SHIFT) & PNP_OPTION_SET_MASK;
+}
+
+static inline unsigned int pnp_option_priority(struct pnp_option *option)
+{
+	return (option->flags >> PNP_OPTION_PRIORITY_SHIFT) &
+	    PNP_OPTION_PRIORITY_MASK;
+}
+
+static inline unsigned int pnp_independent_option(void)
+{
+	return 0;
+}
+
+static inline unsigned int pnp_dependent_option(struct pnp_dev *dev,
+						int priority)
+{
+	unsigned int flags;
+
+	flags = PNP_OPTION_DEPENDENT |
+	    ((dev->num_dependent_sets & PNP_OPTION_SET_MASK) <<
+		PNP_OPTION_SET_SHIFT) |
+	    ((priority & PNP_OPTION_PRIORITY_MASK) <<
+		PNP_OPTION_PRIORITY_SHIFT);
+
+	dev->num_dependent_sets++;
+
+	return flags;
+}
+
+char *pnp_option_priority_name(struct pnp_option *option);
+void dbg_pnp_show_option(struct pnp_dev *dev, struct pnp_option *option);
+
 void pnp_init_resources(struct pnp_dev *dev);
 
 void pnp_fixup_device(struct pnp_dev *dev);
-void pnp_free_option(struct pnp_option *option);
+void pnp_free_options(struct pnp_dev *dev);
 int __pnp_add_device(struct pnp_dev *dev);
 void __pnp_remove_device(struct pnp_dev *dev);
 
drivers/pnp/core.c +2 -2
Index: work10/drivers/pnp/core.c
===================================================================
@@ -118,10 +118,9 @@ static void pnp_release_device(struct de
 {
 	struct pnp_dev *dev = to_pnp_dev(dmdev);
 
-	pnp_free_option(dev->independent);
-	pnp_free_option(dev->dependent);
 	pnp_free_ids(dev);
 	pnp_free_resources(dev);
+	pnp_free_options(dev);
 	kfree(dev);
 }
 
@@ -135,6 +134,7 @@ struct pnp_dev *pnp_alloc_dev(struct pnp
 		return NULL;
 
 	INIT_LIST_HEAD(&dev->resources);
+	INIT_LIST_HEAD(&dev->options);
 	dev->protocol = protocol;
 	dev->number = id;
 	dev->dma_mask = DMA_24BIT_MASK;
drivers/pnp/interface.c +35 -40

103 lines not on this page · raw message

drivers/pnp/isapnp/core.c +31 -37

216 lines not on this page · raw message

drivers/pnp/manager.c +41 -99

178 lines not on this page · raw message

drivers/pnp/pnpacpi/rsparser.c +40 -53

244 lines not on this page · raw message

drivers/pnp/pnpbios/rsparser.c +30 -34

190 lines not on this page · raw message

drivers/pnp/quirks.c +155 -133

359 lines not on this page · raw message

drivers/pnp/resource.c +42 -163

289 lines not on this page · raw message

drivers/pnp/support.c +79 -0

88 lines not on this page · raw message

include/linux/pnp.h +4 -2
Index: work10/include/linux/pnp.h
===================================================================
@@ -1,6 +1,8 @@
 /*
  * Linux Plug and Play Support
  * Copyright by Adam Belay <[email protected]>
+ * (c) Copyright 2008 Hewlett-Packard Development Company, L.P.
+ *	Bjorn Helgaas <[email protected]>
  */
 
 #ifndef _LINUX_PNP_H
@@ -242,9 +244,9 @@ struct pnp_dev {
 
 	int active;
 	int capabilities;
-	struct pnp_option *independent;
-	struct pnp_option *dependent;
+	unsigned int num_dependent_sets;
 	struct list_head resources;
+	struct list_head options;
 
 	char name[PNP_NAME_LEN];	/* contains a human-readable name */
 	int flags;			/* used by protocols */
#34 lore raw

Re: [patch 15/15] PNP: convert resource options to single linked list

Quoted 36 lines · Bjorn Helgaas

ISAPNP, PNPBIOS, and ACPI describe the "possible resource settings" of a device, i.e., the possibilities an OS bus driver has when it assigns I/O port, MMIO, and other resources to the device.

PNP used to maintain this "possible resource setting" information in one independent option structure and a list of dependent option structures for each device. Each of these option structures had lists of I/O, memory, IRQ, and DMA resources, for example:

dev

    independent options
      ind-io0  -> ind-io1  ...
      ind-mem0 -> ind-mem1 ...
      ...
    dependent option set 0
      dep0-io0  -> dep0-io1  ...
      dep0-mem0 -> dep0-mem1 ...
      ...
    dependent option set 1
      dep1-io0  -> dep1-io1  ...
      dep1-mem0 -> dep1-mem1 ...
      ...
    ...

This data structure was designed for ISAPNP, where the OS configures device resource settings by writing directly to configuration registers. The OS can write the registers in arbitrary order much like it writes PCI BARs.

However, for PNPBIOS and ACPI devices, the OS uses firmware interfaces that perform device configuration, and it is important to pass the desired settings to those interfaces in the correct order. The OS learns the correct order by using firmware interfaces that return the "current resource settings" and "possible resource settings," but the option structures above doesn't store the ordering information.

Quoted 7 lines

This patch replaces the independent and dependent lists with a single list of options. For example, a device might have possible resource settings like this:

dev

    options
      ind-io0 -> dep0-io0 -> dep1->io0 -> ind-io1 ...

Just for the record -- due to an ISAPnP bug, ISAPnP doesn't actually at the moment deal with independents following dependents at all (it does not reset the option to independent upon seeing an _STAG_ENDDEP tag) and the rework actually fixes this bug. The ISAPnP spec does recommend that independents precede dependents, but does not guarantee.

Might be good to mention this in the log though? In the unlikely event that some piece of ISAPnP hardware out there actually changes behaviour (to "fixed" ...) that might be a hint in looking at it.

<snip>

drivers/pnp/base.h struct pnp_mem { · line 65

Quoted 5 lines
drivers/pnp/base.h +5 -0
+#define PNP_OPTION_DEPENDENT		0x80000000
+#define PNP_OPTION_SET_MASK		0xff
+#define PNP_OPTION_SET_SHIFT		16
+#define PNP_OPTION_PRIORITY_MASK	0xffff
+#define PNP_OPTION_PRIORITY_SHIFT	0

I checked, and ISAPnP and PnPBIOS definitely limit the priority to 8-bit and ACPI seems to as well meaning the (only) reason for using 16 would be the RES_PRIORITY_INVALID value.

I have on the other hand not encountered text limiting the number of dependents sets to 255 nor do I believe the old code enforced this?

Yes, I suppose this is exceedingly unlikely to be a practical issue.

<snip>

Quoted 4 lines

static void pnp_print_option(pnp_info_buffer_t * buffer, char *space,

drivers/pnp/interface.c +1 -1
-			     struct pnp_option *option, int dep)
+			     struct pnp_option *option)
 

drivers/pnp/interface.c static void pnp_print_mem(pnp_info_buffe · line 198

Quoted 10 lines
drivers/pnp/interface.c +10 -0
+	switch (option->type) {
+	case IORESOURCE_IO:
+		pnp_print_port(buffer, space, &option->u.port);
+		break;
+	case IORESOURCE_MEM:
+		pnp_print_mem(buffer, space, &option->u.mem);
+		break;
+	case IORESOURCE_IRQ:
+		pnp_print_irq(buffer, space, &option->u.irq);
+		break;

I believe it would be good if pnp_print_irq() now also displayed "(optional)" if the flag is set.

Quoted 5 lines
drivers/pnp/isapnp/core.c +0 -1
@@ -659,26 +654,24 @@ static int __init isapnp_create_device(s
 				priority = 0x100 | tmp[0];
 				size = 0;
 			}
-			option = pnp_register_dependent_option(dev, priority);

drivers/pnp/isapnp/core.c static int __init isapnp_create_device(s · line 662

Quoted 10 lines
drivers/pnp/isapnp/core.c +2 -4
-			if (!option)
-				return 1;
+			option_flags = pnp_dependent_option(dev, priority);
 			break;
 		case _STAG_ENDDEP:
 			if (size != 0)
 				goto __skip;
-			priority = 0;
-			dev_dbg(&dev->dev, "end dependent options\n");
+			option_flags = pnp_independent_option();

(here is the bugfix)

Quoted 100 lines
drivers/pnp/manager.c +25 -68
-static int pnp_assign_resources(struct pnp_dev *dev, int depnum)
+static int pnp_assign_resources(struct pnp_dev *dev, int set)
 {
-	struct pnp_port *port;
-	struct pnp_mem *mem;
-	struct pnp_irq *irq;
-	struct pnp_dma *dma;
+	struct pnp_option *option;
 	int nport = 0, nmem = 0, nirq = 0, ndma = 0;
+	int ret = 0;
 
-	dbg_pnp_show_resources(dev, "before pnp_assign_resources");
+	dev_dbg(&dev->dev, "pnp_assign_resources, try dependent set %d\n", set);
 	mutex_lock(&pnp_res_mutex);
 	pnp_clean_resource_table(dev);
-	if (dev->independent) {
-		dev_dbg(&dev->dev, "assigning independent options\n");
-		port = dev->independent->port;
-		mem = dev->independent->mem;
-		irq = dev->independent->irq;
-		dma = dev->independent->dma;
-		while (port) {
-			if (pnp_assign_port(dev, port, nport) < 0)
-				goto fail;
-			nport++;
-			port = port->next;
-		}
-		while (mem) {
-			if (pnp_assign_mem(dev, mem, nmem) < 0)
-				goto fail;
-			nmem++;
-			mem = mem->next;
-		}
-		while (irq) {
-			if (pnp_assign_irq(dev, irq, nirq) < 0)
-				goto fail;
-			nirq++;
-			irq = irq->next;
-		}
-		while (dma) {
-			if (pnp_assign_dma(dev, dma, ndma) < 0)
-				goto fail;
-			ndma++;
-			dma = dma->next;
-		}
-	}
 
-	if (depnum) {
-		struct pnp_option *dep;
-		int i;
-
-		dev_dbg(&dev->dev, "assigning dependent option %d\n", depnum);
-		for (i = 1, dep = dev->dependent; i < depnum;
-		     i++, dep = dep->next)
-			if (!dep)
-				goto fail;
-		port = dep->port;
-		mem = dep->mem;
-		irq = dep->irq;
-		dma = dep->dma;
-		while (port) {
-			if (pnp_assign_port(dev, port, nport) < 0)
-				goto fail;
-			nport++;
-			port = port->next;
-		}
-		while (mem) {
-			if (pnp_assign_mem(dev, mem, nmem) < 0)
-				goto fail;
-			nmem++;
-			mem = mem->next;
-		}
-		while (irq) {
-			if (pnp_assign_irq(dev, irq, nirq) < 0)
-				goto fail;
-			nirq++;
-			irq = irq->next;
+	list_for_each_entry(option, &dev->options, list) {
+		if (pnp_option_is_dependent(option) &&
+		    pnp_option_set(option) != set)
+				continue;
+
+		switch (option->type) {
+		case IORESOURCE_IO:
+			ret = pnp_assign_port(dev, &option->u.port, nport++);
+			break;
+		case IORESOURCE_MEM:
+			ret = pnp_assign_mem(dev, &option->u.mem, nmem++);
+			break;
+		case IORESOURCE_IRQ:
+			ret = pnp_assign_irq(dev, &option->u.irq, nirq++);
+			break;
+		case IORESOURCE_DMA:
+			ret = pnp_assign_dma(dev, &option->u.dma, ndma++);
+			break;
+		default:
+			ret = -EINVAL;
+			break;
 		}
-		while (dma) {

drivers/pnp/manager.c static void pnp_clean_resource_table(str · line 269

Quoted 10 lines
drivers/pnp/manager.c +3 -7
-			if (pnp_assign_dma(dev, dma, ndma) < 0)
-				goto fail;
-			ndma++;
-			dma = dma->next;
-		}
-	} else if (dev->dependent)
-		goto fail;
+		if (ret < 0)
+			break;
+	}

Mmm. Previously when it failed halfway through it re-cleared the resources (at label fail). Does it want to do so now also?

Quoted 26 lines
drivers/pnp/manager.c +6 -10
 	mutex_unlock(&pnp_res_mutex);
-	dbg_pnp_show_resources(dev, "after pnp_assign_resources");
-	return 1;
-
-fail:
-	pnp_clean_resource_table(dev);
-	mutex_unlock(&pnp_res_mutex);
-	dbg_pnp_show_resources(dev, "after pnp_assign_resources (failed)");
-	return 0;
+	if (ret == 0)
+		dbg_pnp_show_resources(dev, "pnp_assign_resources succeeded");
+	else
+		dev_dbg(&dev->dev, "pnp_assign_resources failed (%d)\n", ret);
+	return ret;
 }
 
 /**
@@ -332,29 +282,21 @@ fail:
  */
 int pnp_auto_config_dev(struct pnp_dev *dev)
 {
-	struct pnp_option *dep;
-	int i = 1;
+	int i, ret = 0;
 
 	if (!pnp_can_configure(dev)) {

drivers/pnp/manager.c fail: · line 295

Quoted 10 lines
drivers/pnp/manager.c +3 -2
 		dev_dbg(&dev->dev, "configuration not supported\n");
 		return -ENODEV;
 	}
 
-	if (!dev->dependent) {
-		if (pnp_assign_resources(dev, 0))
+	for (i = 0; i == 0 || i < dev->num_dependent_sets; i++) {
+		ret = pnp_assign_resources(dev, i);
+		if (ret == 0)
 			return 0;

Eeeew. Perhaps:

i = 0;

do {
	ret = pnp_assign_resources(dev, i);
	if (ret == 0)
		return 0;
} while (++i < dev->num_dependent_sets);

<snip>

Quoted 70 lines

Index: work10/drivers/pnp/quirks.c
===================================================================

drivers/pnp/quirks.c +36 -14
@@ -5,6 +5,8 @@
  *  when building up the resource structure for the first time.
  *
  *  Copyright (c) 2000 Peter Denison <[email protected]>
+ *  (c) Copyright 2008 Hewlett-Packard Development Company, L.P.
+ *	Bjorn Helgaas <[email protected]>
  *
  *  Heavily based on PCI quirks handling which is
  *
@@ -20,188 +22,208 @@
 #include <linux/kallsyms.h>
 #include "base.h"
 
+static void quirk_awe32_add_ports(struct pnp_dev *dev,
+				  struct pnp_option *option,
+				  unsigned int offset)
+{
+	struct pnp_option *new_option;
+
+	new_option = kmalloc(sizeof(struct pnp_option), GFP_KERNEL);
+	if (!new_option) {
+		dev_err(&dev->dev, "couldn't add ioport region to option set "
+			"%d\n", pnp_option_set(option));
+		return;
+	}
+
+	*new_option = *option;
+	new_option->u.port.min += offset;
+	new_option->u.port.max += offset;
+	list_add(&new_option->list, &option->list);
+
+	dev_info(&dev->dev, "added ioport region %#llx-%#llx to set %d\n",
+		(unsigned long long) new_option->u.port.min,
+		(unsigned long long) new_option->u.port.max,
+		pnp_option_set(option));
+}
+
 static void quirk_awe32_resources(struct pnp_dev *dev)
 {
-	struct pnp_port *port, *port2, *port3;
-	struct pnp_option *res = dev->dependent;
+	struct pnp_option *option;
+	unsigned int set = ~0;
 
 	/*
-	 * Unfortunately the isapnp_add_port_resource is too tightly bound
-	 * into the PnP discovery sequence, and cannot be used. Link in the
-	 * two extra ports (at offset 0x400 and 0x800 from the one given) by
-	 * hand.
+	 * Add two extra ioport regions (at offset 0x400 and 0x800 from the
+	 * one given) to every dependent option set.
 	 */
-	for (; res; res = res->next) {
-		port2 = pnp_alloc(sizeof(struct pnp_port));
-		if (!port2)
-			return;
-		port3 = pnp_alloc(sizeof(struct pnp_port));
-		if (!port3) {
-			kfree(port2);
-			return;
+	list_for_each_entry(option, &dev->options, list) {
+		if (pnp_option_is_dependent(option) &&
+		    pnp_option_set(option) != set) {
+			set = pnp_option_set(option);
+			quirk_awe32_add_ports(dev, option, 0x800);
+			quirk_awe32_add_ports(dev, option, 0x400);

drivers/pnp/quirks.c line 51

Quoted 10 lines
drivers/pnp/quirks.c +0 -9
 		}
-		port = res->port;
-		memcpy(port2, port, sizeof(struct pnp_port));
-		memcpy(port3, port, sizeof(struct pnp_port));
-		port->next = port2;
-		port2->next = port3;
-		port2->min += 0x400;
-		port2->max += 0x400;
-		port3->min += 0x800;
-		port3->max += 0x800;

Why do you do 0x800, 0x400 in that order? Shouldn't it just be 0x400, 0x800 to mimick the old order?

Quoted 34 lines
drivers/pnp/quirks.c +11 -16
-		dev_info(&dev->dev,
-			"AWE32 quirk - added ioports 0x%lx and 0x%lx\n",
-			(unsigned long)port2->min,
-			(unsigned long)port3->min);
 	}
 }
 
 static void quirk_cmi8330_resources(struct pnp_dev *dev)
 {
-	struct pnp_option *res = dev->dependent;
-	unsigned long tmp;
-
-	for (; res; res = res->next) {
-
-		struct pnp_irq *irq;
-		struct pnp_dma *dma;
+	struct pnp_option *option;
+	struct pnp_irq *irq;
+	struct pnp_dma *dma;
 
-		for (irq = res->irq; irq; irq = irq->next) {	// Valid irqs are 5, 7, 10
-			tmp = 0x04A0;
-			bitmap_copy(irq->map.bits, &tmp, 16);	// 0000 0100 1010 0000
-		}
+	list_for_each_entry(option, &dev->options, list) {
+		if (!pnp_option_is_dependent(option))
+			continue;
 
-		for (dma = res->dma; dma; dma = dma->next)	// Valid 8bit dma channels are 1,3
+		if (option->type == IORESOURCE_IRQ) {
+			irq = &option->u.irq;
+			bitmap_zero(irq->map.bits, PNP_IRQ_NR);
+			__set_bit(5, irq->map.bits);
+			__set_bit(7, irq->map.bits);

drivers/pnp/quirks.c line 91

Quoted 10 lines
drivers/pnp/quirks.c +8 -1
+			__set_bit(10, irq->map.bits);
+			dev_info(&dev->dev, "set possible IRQs in "
+				 "option set %d to 5, 7, 10\n",
+				 pnp_option_set(option));
+		} else if (option->type == IORESOURCE_DMA) {
+			dma = &option->u.dma;
 			if ((dma->flags & IORESOURCE_DMA_TYPE_MASK) ==
-			    IORESOURCE_DMA_8BIT)
+						IORESOURCE_DMA_8BIT &&
+			    dma->map != 0x000A) {

It's a char, so 0x0A? 0x000A makes it looks like it's 16-bit.

drivers/pnp/quirks.c line 96

Quoted 5 lines
drivers/pnp/quirks.c +4 -0
+				dev_info(&dev->dev, "changing possible "
+					 "DMA channel mask in option set %d "
+					 "from %#x to 0xA (1, 3)\n",
+					 pnp_option_set(option), dma->map);
 				dma->map = 0x000A;

And here...

Quoted 10 lines
drivers/pnp/quirks.c +3 -2
+			}
+		}
 	}
-	dev_info(&dev->dev, "CMI8330 quirk - forced possible IRQs to 5, 7, 10 "
-		"and DMA channels to 1, 3\n");
 }
 
 static void quirk_sb16audio_resources(struct pnp_dev *dev)
 {
+	struct pnp_option *option;

drivers/pnp/quirks.c line 112

Quoted 10 lines
drivers/pnp/quirks.c +1 -2
+	unsigned int prev_option_flags = ~0, n = 0;
 	struct pnp_port *port;
-	struct pnp_option *res = dev->dependent;
-	int changed = 0;
 
 	/*
 	 * The default range on the mpu port for these devices is 0x388-0x388.
 	 * Here we increase that range so that two such cards can be
 	 * auto-configured.
 	 */

While you're there -- s/mpu/OPL/.

Quoted 12 lines
drivers/pnp/quirks.c +10 -1
+static void quirk_ad1815_mpu_resources(struct pnp_dev *dev)
 {
-	struct pnp_option *res;
+	struct pnp_option *option, *irq_option = NULL;
+	unsigned int independent_irqs = 0;
+
+	list_for_each_entry(option, &dev->options, list) {
+		if (option->type == IORESOURCE_IRQ &&
+		    !pnp_option_is_dependent(option)) {
+			independent_irqs++;
+			irq_option = option;
+		}

drivers/pnp/quirks.c line 223

Quoted 10 lines
drivers/pnp/quirks.c +3 -4
+	}
 
-	res = dev->dependent;
-	if (!res)
+	if (independent_irqs != 1)
 		return;
 
-	while (res->next)
-		res = res->next;
+	irq_option->flags |= IORESOURCE_IRQ_OPTIONAL;

You're in maze of unsigned variables, all named flags...

irq_option->u.irq.flags |= IORESOURCE_IRQ_OPTIONAL;

This was the thing that made things not work when I tested -- on an AD1815...

drivers/pnp/quirks.c line 226

Quoted 4 lines
drivers/pnp/quirks.c +2 -1
+	dev_info(&dev->dev, "made independent IRQ optional\n");
 
-	res->next = quirk_isapnp_mpu_options(dev);
+	quirk_add_irq_optional_dependent_sets(dev);

And as before, this one be gone.

The other quirks look good -- but I have the hardware and will test them specifically.

Quoted 23 lines

Index: work10/drivers/pnp/resource.c
===================================================================

drivers/pnp/resource.c +5 -2
@@ -3,6 +3,8 @@
  *
  * based on isapnp.c resource management (c) Jaroslav Kysela <[email protected]>
  * Copyright 2003 Adam Belay <[email protected]>
+ * (c) Copyright 2008 Hewlett-Packard Development Company, L.P.
+ *	Bjorn Helgaas <[email protected]>
  */
 
 #include <linux/module.h>
@@ -28,78 +30,37 @@ static int pnp_reserve_mem[16] = {[0 ...
  * option registration
  */
 
-struct pnp_option *pnp_build_option(int priority)
+struct pnp_option *pnp_build_option(struct pnp_dev *dev,
+					   unsigned long type,
+					   unsigned int option_flags)
 {
-	struct pnp_option *option = pnp_alloc(sizeof(struct pnp_option));

drivers/pnp/resource.c static int pnp_reserve_mem[16] = {[0 ... · line 41

Quoted 10 lines
drivers/pnp/resource.c +2 -4
+	struct pnp_option *option;
 
+	option = kzalloc(sizeof(struct pnp_option), GFP_KERNEL);
 	if (!option)
 		return NULL;
 
-	option->priority = priority & 0xff;
-	/* make sure the priority is valid */
-	if (option->priority > PNP_RES_PRIORITY_FUNCTIONAL)
-		option->priority = PNP_RES_PRIORITY_INVALID;

Dropping this made the 0x100 | prio ISAPnP/PnPBIOS bug appear. That 0x100 should go anyway but perhaps this limiting is still a good idea?

drivers/pnp/resource.c static int pnp_reserve_mem[16] = {[0 ... · line 48

Quoted 6 lines
drivers/pnp/resource.c +3 -0
+	option->flags = option_flags;
+	option->type = type;
 
+	list_add_tail(&option->list, &dev->options);
 	return option;
 }

Rene.

#35 lore raw

Re: [patch 15/15] PNP: convert resource options to single linked list

Quoted 11 lines · Rene Herman

On 31-05-08 00:49, Bjorn Helgaas wrote:

Just for the record -- due to an ISAPnP bug, ISAPnP doesn't actually at the moment deal with independents following dependents at all (it does not reset the option to independent upon seeing an _STAG_ENDDEP tag) and the rework actually fixes this bug. The ISAPnP spec does recommend that independents precede dependents, but does not guarantee.

Might be good to mention this in the log though? In the unlikely event that some piece of ISAPnP hardware out there actually changes behaviour (to "fixed" ...) that might be a hint in looking at it.

I split that bugfix into a separate patch; thanks for pointing this out.

Quoted 10 lines

drivers/pnp/base.h struct pnp_mem { · line 65

Quoted 5 lines
drivers/pnp/base.h +5 -0
+#define PNP_OPTION_DEPENDENT		0x80000000
+#define PNP_OPTION_SET_MASK		0xff
+#define PNP_OPTION_SET_SHIFT		16
+#define PNP_OPTION_PRIORITY_MASK	0xffff
+#define PNP_OPTION_PRIORITY_SHIFT	0

I checked, and ISAPnP and PnPBIOS definitely limit the priority to 8-bit and ACPI seems to as well meaning the (only) reason for using 16 would be the RES_PRIORITY_INVALID value.

Quoted 4 lines

I have on the other hand not encountered text limiting the number of dependents sets to 255 nor do I believe the old code enforced this?

Yes, I suppose this is exceedingly unlikely to be a practical issue.

That's definitely backwards. I reversed the sizes, so we'll have 8 bits for the priority byte (including compatibility/performance/ robustness) and 16 bits for the dependent set number. Actually, I made the priority field 12 bits so we'd have space to keep PNP_RES_PRIORITY_INVALID as a truly out-of-band value.

Quoted 4 lines
Quoted 3 lines

static void pnp_print_option(pnp_info_buffer_t * buffer, char *space,

drivers/pnp/interface.c +1 -1
-			     struct pnp_option *option, int dep)
+			     struct pnp_option *option)
Quoted 13 lines

drivers/pnp/interface.c static void pnp_print_mem(pnp_info_buffe · line 198

Quoted 10 lines
drivers/pnp/interface.c +10 -0
+	switch (option->type) {
+	case IORESOURCE_IO:
+		pnp_print_port(buffer, space, &option->u.port);
+		break;
+	case IORESOURCE_MEM:
+		pnp_print_mem(buffer, space, &option->u.mem);
+		break;
+	case IORESOURCE_IRQ:
+		pnp_print_irq(buffer, space, &option->u.irq);
+		break;

I believe it would be good if pnp_print_irq() now also displayed "(optional)" if the flag is set.

I agree; I added this to the patch that added IORESOURCE_IRQ_OPTIONAL.

Quoted 9 lines
Quoted 9 lines
drivers/pnp/isapnp/core.c +1 -3
@@ -659,26 +654,24 @@ static int __init isapnp_create_device(s
 				priority = 0x100 | tmp[0];
 				size = 0;
 			}
-			option = pnp_register_dependent_option(dev, priority);
-			if (!option)
-				return 1;
+			option_flags = pnp_dependent_option(dev, priority);
 			break;
Quoted 8 lines

drivers/pnp/isapnp/core.c static int __init isapnp_create_device(s · line 662

Quoted 6 lines
drivers/pnp/isapnp/core.c +1 -2
 		case _STAG_ENDDEP:
 			if (size != 0)
 				goto __skip;
-			priority = 0;
-			dev_dbg(&dev->dev, "end dependent options\n");
+			option_flags = pnp_independent_option();

(here is the bugfix)

Yep, I split into a separate patch as mentioned above.

Quoted 6 lines

drivers/pnp/manager.c static void pnp_clean_resource_table(str · line 236

Quoted 4 lines
drivers/pnp/manager.c +1 -1
-static int pnp_assign_resources(struct pnp_dev *dev, int depnum)
+static int pnp_assign_resources(struct pnp_dev *dev, int set)
 {
...

Mmm. Previously when it failed halfway through it re-cleared the resources (at label fail). Does it want to do so now also?

Yes, I suppose so. I can't remember why I removed that, but it shouldn't hurt, so I added it back.

Quoted 39 lines
Quoted 26 lines
drivers/pnp/manager.c +6 -10
 	mutex_unlock(&pnp_res_mutex);
-	dbg_pnp_show_resources(dev, "after pnp_assign_resources");
-	return 1;
-
-fail:
-	pnp_clean_resource_table(dev);
-	mutex_unlock(&pnp_res_mutex);
-	dbg_pnp_show_resources(dev, "after pnp_assign_resources (failed)");
-	return 0;
+	if (ret == 0)
+		dbg_pnp_show_resources(dev, "pnp_assign_resources succeeded");
+	else
+		dev_dbg(&dev->dev, "pnp_assign_resources failed (%d)\n", ret);
+	return ret;
 }
 
 /**
@@ -332,29 +282,21 @@ fail:
  */
 int pnp_auto_config_dev(struct pnp_dev *dev)
 {
-	struct pnp_option *dep;
-	int i = 1;
+	int i, ret = 0;
 
 	if (!pnp_can_configure(dev)) {

drivers/pnp/manager.c fail: · line 295

Quoted 10 lines
drivers/pnp/manager.c +3 -2
 		dev_dbg(&dev->dev, "configuration not supported\n");
 		return -ENODEV;
 	}
 
-	if (!dev->dependent) {
-		if (pnp_assign_resources(dev, 0))
+	for (i = 0; i == 0 || i < dev->num_dependent_sets; i++) {
+		ret = pnp_assign_resources(dev, i);
+		if (ret == 0)
 			return 0;

Eeeew. Perhaps:

Quoted 6 lines

i = 0;

do {
	ret = pnp_assign_resources(dev, i);
	if (ret == 0)
		return 0;
} while (++i < dev->num_dependent_sets);

Heh :-) I vacillated on that one because I have a personal aversion to "do { ... } while ()", especially with a pre-increment. How would you feel about this alternative?

        ret = pnp_assign_resources(dev, 0);
        if (ret == 0)
                return 0;

        for (i = 1; i < dev->num_dependent_sets; i++) {
                ret = pnp_assign_resources(dev, i);
                if (ret == 0)
                        return 0;
        }
Quoted 7 lines

drivers/pnp/quirks.c line 51

Quoted 4 lines
drivers/pnp/quirks.c +0 -4
-		port2->min += 0x400;
-		port2->max += 0x400;
-		port3->min += 0x800;
-		port3->max += 0x800;

Why do you do 0x800, 0x400 in that order? Shouldn't it just be 0x400, 0x800 to mimick the old order?

I think they do end up in the correct order because I'm passing the same list_head to both list_add() calls, e.g., we'll have something like this:

    io -> ...
    io -> (io + 0x800) -> ...
    io -> (io + 0x400) -> (io + 0x800) -> ...
Quoted 9 lines

drivers/pnp/quirks.c line 91

Quoted 6 lines
drivers/pnp/quirks.c +4 -1
+		} else if (option->type == IORESOURCE_DMA) {
+			dma = &option->u.dma;
 			if ((dma->flags & IORESOURCE_DMA_TYPE_MASK) ==
-			    IORESOURCE_DMA_8BIT)
+						IORESOURCE_DMA_8BIT &&
+			    dma->map != 0x000A) {

It's a char, so 0x0A? 0x000A makes it looks like it's 16-bit.

Quoted 7 lines

drivers/pnp/quirks.c line 96

Quoted 5 lines
drivers/pnp/quirks.c +4 -0
+				dev_info(&dev->dev, "changing possible "
+					 "DMA channel mask in option set %d "
+					 "from %#x to 0xA (1, 3)\n",
+					 pnp_option_set(option), dma->map);
 				dma->map = 0x000A;

And here...

Makes sense; I changed this as well as the dev_info() formats.

Quoted 7 lines

drivers/pnp/quirks.c line 112

Quoted 5 lines
drivers/pnp/quirks.c +0 -0
 	/*
 	 * The default range on the mpu port for these devices is 0x388-0x388.
 	 * Here we increase that range so that two such cards can be
 	 * auto-configured.
 	 */

While you're there -- s/mpu/OPL/.

Done.

Quoted 25 lines
Quoted 12 lines
drivers/pnp/quirks.c +10 -1
+static void quirk_ad1815_mpu_resources(struct pnp_dev *dev)
 {
-	struct pnp_option *res;
+	struct pnp_option *option, *irq_option = NULL;
+	unsigned int independent_irqs = 0;
+
+	list_for_each_entry(option, &dev->options, list) {
+		if (option->type == IORESOURCE_IRQ &&
+		    !pnp_option_is_dependent(option)) {
+			independent_irqs++;
+			irq_option = option;
+		}

drivers/pnp/quirks.c line 223

Quoted 10 lines
drivers/pnp/quirks.c +3 -4
+	}
 
-	res = dev->dependent;
-	if (!res)
+	if (independent_irqs != 1)
 		return;
 
-	while (res->next)
-		res = res->next;
+	irq_option->flags |= IORESOURCE_IRQ_OPTIONAL;

You're in maze of unsigned variables, all named flags...

Quoted 4 lines

irq_option->u.irq.flags |= IORESOURCE_IRQ_OPTIONAL;

This was the thing that made things not work when I tested -- on an AD1815...

Ah, of course, thanks. I changed "irq_option" to a "struct pnp_irq *irq" like I should have done to begin with.

Quoted 6 lines

drivers/pnp/quirks.c line 226

Quoted 4 lines
drivers/pnp/quirks.c +2 -1
+	dev_info(&dev->dev, "made independent IRQ optional\n");
 
-	res->next = quirk_isapnp_mpu_options(dev);
+	quirk_add_irq_optional_dependent_sets(dev);

And as before, this one be gone.

OK, great. I wasn't sure I had understood those quirks correctly, so thanks for pointing this out.

Quoted 12 lines
Quoted 12 lines
drivers/pnp/resource.c +5 -2
-struct pnp_option *pnp_build_option(int priority)
+struct pnp_option *pnp_build_option(struct pnp_dev *dev,
+					   unsigned long type,
+					   unsigned int option_flags)
 {
-	struct pnp_option *option = pnp_alloc(sizeof(struct pnp_option));
+	struct pnp_option *option;
 
+	option = kzalloc(sizeof(struct pnp_option), GFP_KERNEL);
 	if (!option)
 		return NULL;
Quoted 7 lines

drivers/pnp/resource.c static int pnp_reserve_mem[16] = {[0 ... · line 41

Quoted 4 lines
drivers/pnp/resource.c +0 -4
-	option->priority = priority & 0xff;
-	/* make sure the priority is valid */
-	if (option->priority > PNP_RES_PRIORITY_FUNCTIONAL)
-		option->priority = PNP_RES_PRIORITY_INVALID;

Dropping this made the 0x100 | prio ISAPnP/PnPBIOS bug appear. That 0x100 should go anyway but perhaps this limiting is still a good idea?

Yes; I added the check back to pnp_dependent_option().

PNP_RES_PRIORITY_INVALID was previously 65536, which requires a 16-bit field. I changed it to 0xfff to fit in the 12-bit field I mentioned earlier.

I need to go back over all your comments and make sure I've addressed them all, then I'll post the revised patches, hopefully tomorrow.

Thanks again for all your work reviewing and testing these. It's been incredibly useful.

Bjorn

#36 lore raw

Re: [patch 15/15] PNP: convert resource options to single linked list

Quoted 5 lines · Bjorn Helgaas

That's definitely backwards. I reversed the sizes, so we'll have 8 bits for the priority byte (including compatibility/performance/ robustness) and 16 bits for the dependent set number. Actually, I made the priority field 12 bits so we'd have space to keep PNP_RES_PRIORITY_INVALID as a truly out-of-band value.

Sounds perfect.

Quoted 17 lines
Quoted 6 lines

drivers/pnp/manager.c fail: · line 295

Quoted 4 lines
drivers/pnp/manager.c +3 -0
+	for (i = 0; i == 0 || i < dev->num_dependent_sets; i++) {
+		ret = pnp_assign_resources(dev, i);
+		if (ret == 0)
 			return 0;

Eeeew. Perhaps:

Quoted 6 lines

i = 0;

do {
	ret = pnp_assign_resources(dev, i);
	if (ret == 0)
		return 0;
} while (++i < dev->num_dependent_sets);

Heh :-) I vacillated on that one because I have a personal aversion to "do { ... } while ()", especially with a pre-increment. How would you feel about this alternative?

Quoted 9 lines
        ret = pnp_assign_resources(dev, 0);
        if (ret == 0)
                return 0;

        for (i = 1; i < dev->num_dependent_sets; i++) {
                ret = pnp_assign_resources(dev, i);
                if (ret == 0)
                        return 0;
        }

You could fix the pre-increment by sticking a i++ inside the loop body but there's no arguing with personal aversions...

Yes, I think the latter is better. Straight-forward and clear.

Quoted 9 lines
Quoted 1 line

Why do you do 0x800, 0x400 in that order? Shouldn't it just be 0x400, 0x800 to mimick the old order?

I think they do end up in the correct order because I'm passing the same list_head to both list_add() calls, e.g., we'll have something like this:

    io -> ...
    io -> (io + 0x800) -> ...
    io -> (io + 0x400) -> (io + 0x800) -> ...

Yep. Just needed to see it happen once in the quirk testing I just now did.

Quoted 5 lines

I need to go back over all your comments and make sure I've addressed them all, then I'll post the revised patches, hopefully tomorrow.

Thanks again for all your work reviewing and testing these. It's been incredibly useful.

I've been impressed by this work. This is a good redesign of PnP with a fully bisectable way to get there. And PnP was in need of some work...

Rene.

#37 lore raw

Re: [patch 15/15] PNP: convert resource options to single linked list

In reply to Rene Herman
Quoted 1 line · Rene Herman

The other quirks look good -- but I have the hardware and will test them specifically.

The other quirks are good (In the sense that they work as before. The comments below doubting them have nothing to do with Bjorn reworking them). The options display is with the 0x100 | prio thing fixed locally already.

== 1 == quirk_awe32_resources, CTL0022:

* pre-quirk:

Dependent: 00 - Priority preferred
port 0x620-0x620, align 0x0, size 0x4, 16-bit address decoding
Dependent: 01 - Priority acceptable
port 0x620-0x680, align 0x1f, size 0x4, 16-bit address decoding

* post-quirk:

Dependent: 00 - Priority preferred
port 0x620-0x620, align 0x0, size 0x4, 16-bit address decoding port 0xa20-0xa20, align 0x0, size 0x4, 16-bit address decoding port 0xe20-0xe20, align 0x0, size 0x4, 16-bit address decoding
Dependent: 01 - Priority acceptable
port 0x620-0x680, align 0x1f, size 0x4, 16-bit address decoding port 0xa20-0xa80, align 0x1f, size 0x4, 16-bit address decoding port 0xe20-0xe80, align 0x1f, size 0x4, 16-bit address decoding

I actually expect this quirk to be totally bogus. This adds ports which isapnp_set_resources is then going to try to program into hardware which wouldn't be expecting them. The ALSA driver only references port0 (the 0x620 one) and hardcodes the two other ports at +0x400 and +0x800 itself. I expect the issue is simply that the offsetted ones alias and somebody once thought this could be a way to just reserve those or something.

It's been there since the dawning of time though. Will look at some other time. Things work fine.

== 2 == quirk_cmi8330_resources, @X@0001 (Invalid ID!)

* pre-quirk:

Dependent: 00 - Priority preferred
port 0x220-0x220, align 0x0, size 0x10, 10-bit address decoding irq 5 High-Edge
dma 1 8-bit byte-count compatible
dma 5 16-bit word-count compatible
Dependent: 01 - Priority acceptable
port 0x220-0x240, align 0x1f, size 0x10, 10-bit address decoding irq 5,7,2/9,10 High-Edge
dma 0,1,3 8-bit byte-count compatible
dma 5,7 16-bit word-count compatible
Dependent: 02 - Priority acceptable
port 0x220-0x240, align 0x1f, size 0x10, 10-bit address decoding irq 5,7,2/9,10,11,12 High-Edge
dma 0,1,3 8-bit byte-count compatible
dma 5,7 16-bit word-count compatible

* post-quirk:

Dependent: 00 - Priority preferred
port 0x220-0x220, align 0x0, size 0x10, 10-bit address decoding irq 5,7,10 High-Edge
dma 1,3 8-bit byte-count compatible
dma 5 16-bit word-count compatible
Dependent: 01 - Priority acceptable
port 0x220-0x240, align 0x1f, size 0x10, 10-bit address decoding irq 5,7,10 High-Edge
dma 1,3 8-bit byte-count compatible
dma 5,7 16-bit word-count compatible
Dependent: 02 - Priority acceptable
port 0x220-0x240, align 0x1f, size 0x10, 10-bit address decoding irq 5,7,10 High-Edge
dma 1,3 8-bit byte-count compatible
dma 5,7 16-bit word-count compatible

I'll need to verify if this wasn't just someone with a busted DMA channel 0 and too few free interrupts. Unlikely quirk...

== 3 == quirk_sb16audio_resources, CTL0042:

* pre-quirk:

Dependent: 00 - Priority preferred
irq 5 High-Edge
dma 1 8-bit byte-count compatible
dma 5 16-bit word-count compatible
port 0x220-0x220, align 0x0, size 0x10, 16-bit address decoding port 0x330-0x330, align 0x0, size 0x2, 16-bit address decoding port 0x388-0x388, align 0x0, size 0x4, 16-bit address decoding
Dependent: 01 - Priority acceptable
irq 5,7,2/9,10 High-Edge
dma 0,1,3 8-bit byte-count compatible
dma 5,6,7 16-bit word-count compatible
port 0x220-0x280, align 0x1f, size 0x10, 16-bit address decoding port 0x300-0x330, align 0x2f, size 0x2, 16-bit address decoding port 0x388-0x388, align 0x0, size 0x4, 16-bit address decoding
Dependent: 02 - Priority acceptable
irq 5,7,2/9,10 High-Edge
dma 0,1,3 8-bit byte-count compatible
dma 5,6,7 16-bit word-count compatible
port 0x220-0x280, align 0x1f, size 0x10, 16-bit address decoding port 0x300-0x330, align 0x2f, size 0x2, 16-bit address decoding
Dependent: 03 - Priority acceptable
irq 5,7,2/9,10 High-Edge
dma 0,1,3 8-bit byte-count compatible
dma 5,6,7 16-bit word-count compatible
port 0x220-0x280, align 0x1f, size 0x10, 16-bit address decoding
Dependent: 04 - Priority acceptable
irq 5,7,2/9,10 High-Edge
dma 0,1,3 8-bit byte-count compatible
port 0x220-0x280, align 0x1f, size 0x10, 16-bit address decoding port 0x300-0x330, align 0x2f, size 0x2, 16-bit address decoding port 0x388-0x388, align 0x0, size 0x4, 16-bit address decoding
Dependent: 05 - Priority acceptable
irq 5,7,2/9,10 High-Edge
dma 0,1,3 8-bit byte-count compatible
port 0x220-0x280, align 0x1f, size 0x10, 16-bit address decoding port 0x300-0x330, align 0x2f, size 0x2, 16-bit address decoding
Dependent: 06 - Priority acceptable
irq 5,7,2/9,10 High-Edge
dma 0,1,3 8-bit byte-count compatible
port 0x220-0x280, align 0x1f, size 0x10, 16-bit address decoding
Dependent: 07 - Priority functional
irq 5,7,2/9,10 High-Edge
dma 0,1,3 8-bit byte-count compatible
dma 5,6,7 16-bit word-count compatible
port 0x220-0x280, align 0x1f, size 0x10, 16-bit address decoding port 0x300-0x330, align 0xf, size 0x2, 16-bit address decoding port 0x388-0x394, align 0x3, size 0x4, 16-bit address decoding

* post-quirk:

Dependent: 00 - Priority preferred
irq 5 High-Edge
dma 1 8-bit byte-count compatible
dma 5 16-bit word-count compatible
port 0x220-0x220, align 0x0, size 0x10, 16-bit address decoding port 0x330-0x330, align 0x0, size 0x2, 16-bit address decoding port 0x388-0x3f8, align 0x0, size 0x4, 16-bit address decoding
Dependent: 01 - Priority acceptable
irq 5,7,2/9,10 High-Edge
dma 0,1,3 8-bit byte-count compatible
dma 5,6,7 16-bit word-count compatible
port 0x220-0x280, align 0x1f, size 0x10, 16-bit address decoding port 0x300-0x330, align 0x2f, size 0x2, 16-bit address decoding port 0x388-0x3f8, align 0x0, size 0x4, 16-bit address decoding
Dependent: 02 - Priority acceptable
irq 5,7,2/9,10 High-Edge
dma 0,1,3 8-bit byte-count compatible
dma 5,6,7 16-bit word-count compatible
port 0x220-0x280, align 0x1f, size 0x10, 16-bit address decoding port 0x300-0x330, align 0x2f, size 0x2, 16-bit address decoding
Dependent: 03 - Priority acceptable
irq 5,7,2/9,10 High-Edge
dma 0,1,3 8-bit byte-count compatible
dma 5,6,7 16-bit word-count compatible
port 0x220-0x280, align 0x1f, size 0x10, 16-bit address decoding
Dependent: 04 - Priority acceptable
irq 5,7,2/9,10 High-Edge
dma 0,1,3 8-bit byte-count compatible
port 0x220-0x280, align 0x1f, size 0x10, 16-bit address decoding port 0x300-0x330, align 0x2f, size 0x2, 16-bit address decoding port 0x388-0x3f8, align 0x0, size 0x4, 16-bit address decoding
Dependent: 05 - Priority acceptable
irq 5,7,2/9,10 High-Edge
dma 0,1,3 8-bit byte-count compatible
port 0x220-0x280, align 0x1f, size 0x10, 16-bit address decoding port 0x300-0x330, align 0x2f, size 0x2, 16-bit address decoding
Dependent: 06 - Priority acceptable
irq 5,7,2/9,10 High-Edge
dma 0,1,3 8-bit byte-count compatible
port 0x220-0x280, align 0x1f, size 0x10, 16-bit address decoding
Dependent: 07 - Priority functional
irq 5,7,2/9,10 High-Edge
dma 0,1,3 8-bit byte-count compatible
dma 5,6,7 16-bit word-count compatible
port 0x220-0x280, align 0x1f, size 0x10, 16-bit address decoding port 0x300-0x330, align 0xf, size 0x2, 16-bit address decoding port 0x388-0x394, align 0x3, size 0x4, 16-bit address decoding

I'll need to verify if the OPL chip in fact works when not on 0x388 (to 0x394 as set 7 allows for) or if this was just someone believing it would. I haven't tested all supported IDs (I might have them all) but if there are none that do _not_ allow the OPL to be completely absent as this CTL0042 (an early Soundblaster AWE64) does, this quirk should just go anyway.

=== 4 === quirk_ad1815_mpu_resources, ADS7151

These results are with the dependent cloning already removed locally.

* pre-quirk:

irq 5,7,2/9,11,12 High-Edge
Dependent: 00 - Priority preferred
port 0x330-0x330, align 0x0, size 0x2, 10-bit address decoding
Dependent: 01 - Priority acceptable
port 0x300-0x300, align 0x0, size 0x2, 10-bit address decoding
Dependent: 02 - Priority functional
port 0x100-0x3fe, align 0x1, size 0x2, 10-bit address decoding

* post-quirk:

irq 5,7,2/9,11,12 High-Edge
Dependent: 00 - Priority preferred
port 0x330-0x330, align 0x0, size 0x2, 10-bit address decoding
Dependent: 01 - Priority acceptable
port 0x300-0x300, align 0x0, size 0x2, 10-bit address decoding
Dependent: 02 - Priority functional
port 0x100-0x3fe, align 0x1, size 0x2, 10-bit address decoding

See why that "(optional)" flag display is good? :-) I ofcourse tested things and the flag works great...

== 5 == quirk_add_irq_optional_dependent_sets, ADS7181

* pre-quirk:

Dependent: 00 - Priority preferred
irq 2/9 High-Edge
port 0x330-0x330, align 0xf, size 0x2, 16-bit address decoding
Dependent: 01 - Priority acceptable
irq 2/9 High-Edge
port 0x300-0x330, align 0xf, size 0x2, 16-bit address decoding
Dependent: 02 - Priority functional
irq 2/9,10,11 High-Edge
port 0x300-0x330, align 0xf, size 0x2, 16-bit address decoding

* post-quirk:

Dependent: 00 - Priority preferred
irq 2/9 High-Edge
port 0x330-0x330, align 0xf, size 0x2, 16-bit address decoding
Dependent: 01 - Priority acceptable
irq 2/9 High-Edge
port 0x300-0x330, align 0xf, size 0x2, 16-bit address decoding
Dependent: 02 - Priority functional
irq 2/9,10,11 High-Edge
port 0x300-0x330, align 0xf, size 0x2, 16-bit address decoding
Dependent: 03 - Priority functional
irq 2/9 High-Edge
port 0x330-0x330, align 0xf, size 0x2, 16-bit address decoding
Dependent: 04 - Priority functional
irq 2/9 High-Edge
port 0x300-0x330, align 0xf, size 0x2, 16-bit address decoding
Dependent: 05 - Priority functional
irq 2/9,10,11 High-Edge
port 0x300-0x330, align 0xf, size 0x2, 16-bit address decoding

Again needs the flag display to make sense but as intended and works fine.

The PCI one didn't change here...

Rene.

#38 lore raw

Re: [patch 15/15] PNP: convert resource options to single linked list

On 04-06-08 01:52, Rene Herman wrote:

Mmm. If you care for it:

Quoted 54 lines

=== 4 === quirk_ad1815_mpu_resources, ADS7151

These results are with the dependent cloning already removed locally.

* pre-quirk:

irq 5,7,2/9,11,12 High-Edge
Dependent: 00 - Priority preferred
port 0x330-0x330, align 0x0, size 0x2, 10-bit address decoding
Dependent: 01 - Priority acceptable
port 0x300-0x300, align 0x0, size 0x2, 10-bit address decoding
Dependent: 02 - Priority functional
port 0x100-0x3fe, align 0x1, size 0x2, 10-bit address decoding

* post-quirk:

irq 5,7,2/9,11,12 High-Edge
Dependent: 00 - Priority preferred
port 0x330-0x330, align 0x0, size 0x2, 10-bit address decoding
Dependent: 01 - Priority acceptable
port 0x300-0x300, align 0x0, size 0x2, 10-bit address decoding
Dependent: 02 - Priority functional
port 0x100-0x3fe, align 0x1, size 0x2, 10-bit address decoding

See why that "(optional)" flag display is good? :-) I ofcourse tested things and the flag works great...

== 5 == quirk_add_irq_optional_dependent_sets, ADS7181

* pre-quirk:

Dependent: 00 - Priority preferred
irq 2/9 High-Edge
port 0x330-0x330, align 0xf, size 0x2, 16-bit address decoding
Dependent: 01 - Priority acceptable
irq 2/9 High-Edge
port 0x300-0x330, align 0xf, size 0x2, 16-bit address decoding
Dependent: 02 - Priority functional
irq 2/9,10,11 High-Edge
port 0x300-0x330, align 0xf, size 0x2, 16-bit address decoding

* post-quirk:

Dependent: 00 - Priority preferred
irq 2/9 High-Edge
port 0x330-0x330, align 0xf, size 0x2, 16-bit address decoding
Dependent: 01 - Priority acceptable
irq 2/9 High-Edge
port 0x300-0x330, align 0xf, size 0x2, 16-bit address decoding
Dependent: 02 - Priority functional
irq 2/9,10,11 High-Edge
port 0x300-0x330, align 0xf, size 0x2, 16-bit address decoding
Dependent: 03 - Priority functional

Quoted 8 lines

irq 2/9 High-Edge
port 0x330-0x330, align 0xf, size 0x2, 16-bit address decoding
Dependent: 04 - Priority functional
irq 2/9 High-Edge
port 0x300-0x330, align 0xf, size 0x2, 16-bit address decoding
Dependent: 05 - Priority functional
irq 2/9,10,11 High-Edge
port 0x300-0x330, align 0xf, size 0x2, 16-bit address decoding

ADS7181 in fact might as well delete the IRQ from the dependents and add
"irq 2/9,10,11 High-Edge Optinal" in front as an independent same as ADS7151. That way, all the cloning can go.

I'll probably place that on top if you don't, but you might already want to since it loses all that code. Only difference would be that if IRQ 9 is taken and 10 free, the new situation would grab 330/10 while the old would've taken 300/10, but that's in fact better...

Rene.

#39 lore raw

Re: [patch 15/15] PNP: convert resource options to single linked list

Quoted 5 lines · Rene Herman

On 04-06-08 01:52, Rene Herman wrote:

ADS7181 in fact might as well delete the IRQ from the dependents and add "irq 2/9,10,11 High-Edge Optinal" in front as an independent same as ADS7151. That way, all the cloning can go.

We currently clone for AZT0002 as well as ADS7181. Can we do the same for both? It would be nice to get rid of the cloning code if we can.

Bjorn

#40 lore raw

Re: [patch 15/15] PNP: convert resource options to single linked list

Quoted 9 lines · Bjorn Helgaas
Quoted 4 lines · Rene Herman

On 04-06-08 01:52, Rene Herman wrote:

ADS7181 in fact might as well delete the IRQ from the dependents and add
"irq 2/9,10,11 High-Edge Optinal" in front as an independent same as ADS7151. That way, all the cloning can go.

We currently clone for AZT0002 as well as ADS7181. Can we do the same for both? It would be nice to get rid of the cloning code if we can.

Yes. AZT0002 (the MPU401 on an AZT2320 chip) is the exact same as ADS7181 (the MPU401 on an AD1816 chip).

IORESOURCE_IRQ_OPTIONAL clears the path for doing things better. I see its dependent 2 can then just go entirely in fact.

Hardware says:

Dependent: 00 - Priority preferred
irq 2/9 High-Edge
port 0x330-0x330, align 0xf, size 0x2, 16-bit address decoding
Dependent: 01 - Priority acceptable
irq 2/9 High-Edge
port 0x300-0x330, align 0xf, size 0x2, 16-bit address decoding
Dependent: 02 - Priority functional
irq 2/9,10,11 High-Edge
port 0x300-0x330, align 0xf, size 0x2, 16-bit address decoding

We want it to end up as:

irq 2/9,10,11 High-Edge (Optional)
Dependent: 00 - Priority preferred
port 0x330-0x330, align 0xf, size 0x2, 16-bit address decoding
Dependent: 01 - Priority acceptable
port 0x300-0x330, align 0xf, size 0x2, 16-bit address decoding

So walk dependents deleting IRQs, except last dependent IRQ which is cloned into a new independent (inserted in front would be best for ISAPnP since the spec does recommend this) while making it optional and then just delete the last dependent completely (it would be same as the previous dependent after all).

Rene.

#41 lore raw

Re: [patch 15/15] PNP: convert resource options to single linked list

Quoted 39 lines · Rene Herman
Quoted 10 lines · Bjorn Helgaas
Quoted 5 lines · Rene Herman

On 04-06-08 01:52, Rene Herman wrote:

ADS7181 in fact might as well delete the IRQ from the dependents and add "irq 2/9,10,11 High-Edge Optinal" in front as an independent same as ADS7151. That way, all the cloning can go.

We currently clone for AZT0002 as well as ADS7181. Can we do the same for both? It would be nice to get rid of the cloning code if we can.

Yes. AZT0002 (the MPU401 on an AZT2320 chip) is the exact same as ADS7181 (the MPU401 on an AD1816 chip).

IORESOURCE_IRQ_OPTIONAL clears the path for doing things better. I see its dependent 2 can then just go entirely in fact.

Hardware says:

Dependent: 00 - Priority preferred
irq 2/9 High-Edge
port 0x330-0x330, align 0xf, size 0x2, 16-bit address decoding
Dependent: 01 - Priority acceptable
irq 2/9 High-Edge
port 0x300-0x330, align 0xf, size 0x2, 16-bit address decoding
Dependent: 02 - Priority functional
irq 2/9,10,11 High-Edge
port 0x300-0x330, align 0xf, size 0x2, 16-bit address decoding

We want it to end up as:

irq 2/9,10,11 High-Edge (Optional)
Dependent: 00 - Priority preferred
port 0x330-0x330, align 0xf, size 0x2, 16-bit address decoding
Dependent: 01 - Priority acceptable
port 0x300-0x330, align 0xf, size 0x2, 16-bit address decoding

Quoted 5 lines

So walk dependents deleting IRQs, except last dependent IRQ which is cloned into a new independent (inserted in front would be best for ISAPnP since the spec does recommend this) while making it optional and then just delete the last dependent completely (it would be same as the previous dependent after all).

That would probably simplify things a bit. Although in the general case, I suppose we'd want to make sure the options we delete are a subset of the independent one we add. Will look at this more tomorrow.

Bjorn

#42 lore raw

Re: [patch 15/15] PNP: convert resource options to single linked list

In reply to Bjorn Helgaas

On 31-05-08 00:49, Bjorn Helgaas wrote:

Forgot this comment:

Quoted 83 lines
drivers/pnp/quirks.c +31 -44
 
+static struct pnp_option *pnp_clone_dependent_set(struct pnp_dev *dev,
+						  unsigned int set)
 {
-	struct pnp_option *head = NULL;
-	struct pnp_option *prev = NULL;
-	struct pnp_option *res;
-
-	/*
-	 * Build a functional IRQ-optional variant of each MPU option.
-	 */
-
-	for (res = dev->dependent; res; res = res->next) {
-		struct pnp_option *curr;
-		struct pnp_port *port;
-		struct pnp_port *copy_port;
-		struct pnp_irq *irq;
-		struct pnp_irq *copy_irq;
-
-		port = res->port;
-		irq = res->irq;
-		if (!port || !irq)
-			continue;
+	struct pnp_option *tail = NULL, *first_new_option = NULL;
+	struct pnp_option *option, *new_option;
+	unsigned int flags;
+
+	list_for_each_entry(option, &dev->options, list) {
+		if (pnp_option_is_dependent(option))
+			tail = option;
+	}
+	if (!tail) {
+		dev_err(&dev->dev, "no dependent option sets\n");
+		return NULL;
+	}
 
-		copy_port = pnp_alloc(sizeof *copy_port);
-		if (!copy_port)
-			break;
-
-		copy_irq = pnp_alloc(sizeof *copy_irq);
-		if (!copy_irq) {
-			kfree(copy_port);
-			break;
-		}
+	flags = pnp_dependent_option(dev, PNP_RES_PRIORITY_FUNCTIONAL);
+	list_for_each_entry(option, &dev->options, list) {
+		if (pnp_option_is_dependent(option) &&
+		    pnp_option_set(option) == set) {
+			new_option = kmalloc(sizeof(struct pnp_option),
+					     GFP_KERNEL);
+			if (!new_option) {
+				dev_err(&dev->dev, "couldn't clone dependent "
+					"set %d\n", set);
+				return NULL;
+			}
 
-		*copy_port = *port;
-		copy_port->next = NULL;
+			*new_option = *option;
+			new_option->flags = flags;
+			if (!first_new_option)
+				first_new_option = new_option;
 
-		*copy_irq = *irq;
-		copy_irq->flags |= IORESOURCE_IRQ_OPTIONAL;
-		copy_irq->next = NULL;
-
-		curr = pnp_build_option(PNP_RES_PRIORITY_FUNCTIONAL);
-		if (!curr) {
-			kfree(copy_port);
-			kfree(copy_irq);
-			break;
+			list_add(&new_option->list, &tail->list);
+			tail = new_option;
 		}
-		curr->port = copy_port;
-		curr->irq = copy_irq;
-
-		if (prev)
-			prev->next = curr;

drivers/pnp/quirks.c line 176

Quoted 10 lines
drivers/pnp/quirks.c +1 -6
-		else
-			head = curr;
-		prev = curr;
 	}
-	if (head)
-		dev_info(&dev->dev, "adding IRQ-optional MPU options\n");
 
-	return head;
+	return first_new_option;
 }

This works, but I did the "disconnected chain build" that I did due to finding it particularly clumsy to add to the dependent chain while walking it.

This avoids actual problems due to num_sets = dev->num_dependents_sets in caller and the pnp_option_set(option) == set in the loop (not unlike the first version of the original checked for a present irq) but it's again checking the options it just added itself.

If you feel that's perfectly fine then <shrug> but thought I'd still remark on it in case it wasn't intentional.

Rene.

#43 lore raw

Re: [patch 15/15] PNP: convert resource options to single linked list

Quoted 102 lines · Rene Herman

On 31-05-08 00:49, Bjorn Helgaas wrote:

Forgot this comment:

Quoted 83 lines
drivers/pnp/quirks.c +31 -44
 
+static struct pnp_option *pnp_clone_dependent_set(struct pnp_dev *dev,
+						  unsigned int set)
 {
-	struct pnp_option *head = NULL;
-	struct pnp_option *prev = NULL;
-	struct pnp_option *res;
-
-	/*
-	 * Build a functional IRQ-optional variant of each MPU option.
-	 */
-
-	for (res = dev->dependent; res; res = res->next) {
-		struct pnp_option *curr;
-		struct pnp_port *port;
-		struct pnp_port *copy_port;
-		struct pnp_irq *irq;
-		struct pnp_irq *copy_irq;
-
-		port = res->port;
-		irq = res->irq;
-		if (!port || !irq)
-			continue;
+	struct pnp_option *tail = NULL, *first_new_option = NULL;
+	struct pnp_option *option, *new_option;
+	unsigned int flags;
+
+	list_for_each_entry(option, &dev->options, list) {
+		if (pnp_option_is_dependent(option))
+			tail = option;
+	}
+	if (!tail) {
+		dev_err(&dev->dev, "no dependent option sets\n");
+		return NULL;
+	}
 
-		copy_port = pnp_alloc(sizeof *copy_port);
-		if (!copy_port)
-			break;
-
-		copy_irq = pnp_alloc(sizeof *copy_irq);
-		if (!copy_irq) {
-			kfree(copy_port);
-			break;
-		}
+	flags = pnp_dependent_option(dev, PNP_RES_PRIORITY_FUNCTIONAL);
+	list_for_each_entry(option, &dev->options, list) {
+		if (pnp_option_is_dependent(option) &&
+		    pnp_option_set(option) == set) {
+			new_option = kmalloc(sizeof(struct pnp_option),
+					     GFP_KERNEL);
+			if (!new_option) {
+				dev_err(&dev->dev, "couldn't clone dependent "
+					"set %d\n", set);
+				return NULL;
+			}
 
-		*copy_port = *port;
-		copy_port->next = NULL;
+			*new_option = *option;
+			new_option->flags = flags;
+			if (!first_new_option)
+				first_new_option = new_option;
 
-		*copy_irq = *irq;
-		copy_irq->flags |= IORESOURCE_IRQ_OPTIONAL;
-		copy_irq->next = NULL;
-
-		curr = pnp_build_option(PNP_RES_PRIORITY_FUNCTIONAL);
-		if (!curr) {
-			kfree(copy_port);
-			kfree(copy_irq);
-			break;
+			list_add(&new_option->list, &tail->list);
+			tail = new_option;
 		}
-		curr->port = copy_port;
-		curr->irq = copy_irq;
-
-		if (prev)
-			prev->next = curr;

drivers/pnp/quirks.c line 176

Quoted 10 lines
drivers/pnp/quirks.c +1 -6
-		else
-			head = curr;
-		prev = curr;
 	}
-	if (head)
-		dev_info(&dev->dev, "adding IRQ-optional MPU options\n");
 
-	return head;
+	return first_new_option;
 }

This works, but I did the "disconnected chain build" that I did due to finding it particularly clumsy to add to the dependent chain while walking it.

Quoted 7 lines

This avoids actual problems due to num_sets = dev->num_dependents_sets in caller and the pnp_option_set(option) == set in the loop (not unlike the first version of the original checked for a present irq) but it's again checking the options it just added itself.

If you feel that's perfectly fine then <shrug> but thought I'd still remark on it in case it wasn't intentional.

Hmmm... I think I see what you mean. It should work as-is, but maybe it'd be more elegant to build the new list separately and use list_splice to insert it.

Guess I'll wait for you to confirm whether we can rip out the list clone altogether before trying this out.

Bjorn

#44 lore raw
In reply to Bjorn Helgaas
Quoted 10 lines · Bjorn Helgaas

This patch series converts the PNP resource option structures to a unified linked list. This preserves resource order, which is important for some devices. There's more detail in the comments for the last patch.

Any comments would be welcome.

This depends on some patches that are in -mm, but not yet upstream. In mmotm, these would probably go after pnp-dont-sort-by-type-in-sys-resources.patch

Will look at this in more detail but as first testing feedback -- I need this on top.

Both ISAPnP and PnPBIOS for some or other reason set the priority to 0x100 | prio after which that 0x100 is immediately masked of again in pnp_build_option() leaving just the prio. Your new scheme reserves 16 bits for the priority though meaning the 0x100 survives causing it to be considered "invalid" by at least pnp_option_priority_name() for example.

There cannot be any currently valid reason for the 0x100 it seems given that it's immediately masked of again in pnp_build_option() so let's just get rid of it...

drivers/pnp/isapnp/core.c +2 -2
index d4c6b19..7556887 100644
@@ -648,10 +648,10 @@ static int __init isapnp_create_device(struct pnp_card *card,
 		case _STAG_STARTDEP:
 			if (size > 1)
 				goto __skip;
-			priority = 0x100 | PNP_RES_PRIORITY_ACCEPTABLE;
+			priority = PNP_RES_PRIORITY_ACCEPTABLE;
 			if (size > 0) {
 				isapnp_peek(tmp, size);
-				priority = 0x100 | tmp[0];
+				priority = tmp[0];
 				size = 0;
 			}
 			option_flags = pnp_dependent_option(dev, priority);
drivers/pnp/pnpbios/rsparser.c +2 -2
index e0bea09..a6c9539 100644
@@ -393,9 +393,9 @@ pnpbios_parse_resource_option_data(unsigned char *p, unsigned char *end,
 		case SMALL_TAG_STARTDEP:
 			if (len > 1)
 				goto len_err;
-			priority = 0x100 | PNP_RES_PRIORITY_ACCEPTABLE;
+			priority = PNP_RES_PRIORITY_ACCEPTABLE;
 			if (len > 0)
-				priority = 0x100 | p[1];
+				priority = p[1];
 			option_flags = pnp_dependent_option(dev, priority);
 			break;
 
#45 lore raw
Quoted 22 lines · Rene Herman
Quoted 10 lines · Bjorn Helgaas

This patch series converts the PNP resource option structures to a unified linked list. This preserves resource order, which is important for some devices. There's more detail in the comments for the last patch.

Any comments would be welcome.

This depends on some patches that are in -mm, but not yet upstream. In mmotm, these would probably go after pnp-dont-sort-by-type-in-sys-resources.patch

Will look at this in more detail but as first testing feedback -- I need this on top.

Both ISAPnP and PnPBIOS for some or other reason set the priority to 0x100 | prio after which that 0x100 is immediately masked of again in pnp_build_option() leaving just the prio. Your new scheme reserves 16 bits for the priority though meaning the 0x100 survives causing it to be considered "invalid" by at least pnp_option_priority_name() for example.

Quoted 3 lines

There cannot be any currently valid reason for the 0x100 it seems given that it's immediately masked of again in pnp_build_option() so let's just get rid of it...

I agree, that bit looks superfluous. I added a patch to remove it. Thanks,
Bjorn