device/pnp_device: rewrite pnp_get_ioresource

The rewrite simplifies the code and fixes the limit on the case of IO resources
with the length of 1 byte.

This patch is inspired by the comment of Nico Huber on
Ia99b785dcd9cf56fb236ad7ade54656851f88a5e

If the ones in the mask aren't a continuous block, now a warning message gets
printed.

Change-Id: I0089278f5adf65e8f084580bc5bc1eb2f77b87f7
Signed-off-by: Felix Held <felix-coreboot@felixheld.de>
Reviewed-on: https://review.coreboot.org/27654
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: Patrick Rudolph <siro@das-labor.org>
This commit is contained in:
Felix Held 2018-07-27 02:31:09 +02:00
parent 66ce18c508
commit f2ec648fcb
1 changed files with 23 additions and 32 deletions

View File

@ -7,6 +7,7 @@
* Copyright (C) 2005 Tyan
* (Written by Yinghai Lu <yhlu@tyan.com> for Tyan)
* Copyright (C) 2013 Nico Huber <nico.h@gmx.de>
* Copyright (C) 2018 Felix Held <felix-coreboot@felixheld.de>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -194,8 +195,10 @@ struct device_operations pnp_ops = {
static void pnp_get_ioresource(struct device *dev, u8 index, u16 mask)
{
struct resource *resource;
unsigned moving, gran, step;
unsigned int bit;
/* If none of the mask bits is set, the resource would occupy the whole
IO space leading to IO resource conflicts with the other devices */
if (!mask) {
printk(BIOS_ERR, "ERROR: device %s index %d has no mask.\n",
dev_path(dev), index);
@ -203,43 +206,31 @@ static void pnp_get_ioresource(struct device *dev, u8 index, u16 mask)
}
resource = new_resource(dev, index);
/* Initilize the resource. */
resource->limit = 0xffff;
resource->flags |= IORESOURCE_IO;
/* Get the resource size... */
/* Calculate IO region size which is determined by the first one from
the LSB of the mask. */
for (bit = 0; bit <= 15 && (mask & (1 << bit)) == 0; ++bit)
;
moving = mask;
gran = 15;
step = 1 << gran;
resource->gran = bit;
resource->align = bit;
resource->size = 1 << bit;
/* Find the first bit that moves. */
while ((moving & step) == 0) {
gran--;
step >>= 1;
}
/* Calculate IO region address limit which is determined by the first
one from the MSB of the mask. */
for (bit = 15; bit != 0 && (mask & (1 << bit)) == 0; --bit)
;
/* Now find the first bit that does not move. */
while ((moving & step) != 0) {
gran--;
step >>= 1;
}
resource->limit = (1 << (bit + 1)) - 1;
/*
* Of the moving bits the last bit in the first group,
* tells us the size of this resource.
*/
if ((moving & step) == 0) {
gran++;
step <<= 1;
}
/* Set the resource size and alignment. */
resource->gran = gran;
resource->align = gran;
resource->limit = mask | (step - 1);
resource->size = 1 << gran;
/* The block of ones in the mask is expected to be continuous.
If there is any zero inbetween the block of ones, it is ignored
in the calculation of the resource size and limit. */
if (mask != (resource->limit ^ (resource->size - 1)))
printk(BIOS_WARNING,
"WARNING: mask of device %s index %d is wrong.\n",
dev_path(dev), index);
}
static void get_resources(struct device *dev, struct pnp_info *info)