svn commit: r216674 - head/sys/dev/acpica

Ganbold ganbold at gmail.com
Thu Dec 23 17:08:40 UTC 2010


John,

On 12/23/10 04:27, John Baldwin wrote:
> Author: jhb
> Date: Wed Dec 22 20:27:20 2010
> New Revision: 216674
> URL: http://svn.freebsd.org/changeset/base/216674
>
> Log:
>    Use resource_list_reserve() to reserve I/O port and memory resources for
>    ACPI devices even if they are not allocated by a device driver since the
>    resources are in use and should not be allocated to another device.

Looks like either my laptop's BIOS/firmware is crappy or this commit 
breaks booting.
Following are the images I captured, although it may not be useful:

http://people.freebsd.org/~ganbold/crash1.jpg
http://people.freebsd.org/~ganbold/crash2.jpg

dmesg (without this commit):

http://people.freebsd.org/~ganbold/dmesg.txt

thanks,

Ganbold

> Modified:
>    head/sys/dev/acpica/acpi.c
>    head/sys/dev/acpica/acpivar.h
>
> Modified: head/sys/dev/acpica/acpi.c
> ==============================================================================
> --- head/sys/dev/acpica/acpi.c	Wed Dec 22 19:57:03 2010	(r216673)
> +++ head/sys/dev/acpica/acpi.c	Wed Dec 22 20:27:20 2010	(r216674)
> @@ -116,7 +116,10 @@ static int	acpi_read_ivar(device_t dev,
>   static int	acpi_write_ivar(device_t dev, device_t child, int index,
>   			uintptr_t value);
>   static struct resource_list *acpi_get_rlist(device_t dev, device_t child);
> +static void	acpi_reserve_resources(device_t dev);
>   static int	acpi_sysres_alloc(device_t dev);
> +static int	acpi_set_resource(device_t dev, device_t child, int type,
> +			int rid, u_long start, u_long count);
>   static struct resource *acpi_alloc_resource(device_t bus, device_t child,
>   			int type, int *rid, u_long start, u_long end,
>   			u_long count, u_int flags);
> @@ -187,7 +190,7 @@ static device_method_t acpi_methods[] =
>       DEVMETHOD(bus_read_ivar,		acpi_read_ivar),
>       DEVMETHOD(bus_write_ivar,		acpi_write_ivar),
>       DEVMETHOD(bus_get_resource_list,	acpi_get_rlist),
> -    DEVMETHOD(bus_set_resource,		bus_generic_rl_set_resource),
> +    DEVMETHOD(bus_set_resource,		acpi_set_resource),
>       DEVMETHOD(bus_get_resource,		bus_generic_rl_get_resource),
>       DEVMETHOD(bus_alloc_resource,	acpi_alloc_resource),
>       DEVMETHOD(bus_release_resource,	acpi_release_resource),
> @@ -1109,73 +1112,144 @@ acpi_sysres_alloc(device_t dev)
>       return (0);
>   }
>
> -static struct resource *
> -acpi_alloc_resource(device_t bus, device_t child, int type, int *rid,
> -    u_long start, u_long end, u_long count, u_int flags)
> +static char *pcilink_ids[] = { "PNP0C0F", NULL };
> +static char *sysres_ids[] = { "PNP0C01", "PNP0C02", NULL };
> +
> +/*
> + * Reserve declared resources for devices found during attach once system
> + * resources have been allocated.
> + */
> +static void
> +acpi_reserve_resources(device_t dev)
>   {
> -    ACPI_RESOURCE ares;
> -    struct acpi_device *ad = device_get_ivars(child);
> -    struct resource_list *rl =&ad->ad_rl;
>       struct resource_list_entry *rle;
> -    struct resource *res;
> -    struct rman *rm;
> +    struct resource_list *rl;
> +    struct acpi_device *ad;
> +    struct acpi_softc *sc;
> +    device_t *children;
> +    int child_count, i;
>
> -    res = NULL;
> +    sc = device_get_softc(dev);
> +    if (device_get_children(dev,&children,&child_count) != 0)
> +	return;
> +    for (i = 0; i<  child_count; i++) {
> +	ad = device_get_ivars(children[i]);
> +	rl =&ad->ad_rl;
>
> -    /* We only handle memory and IO resources through rman. */
> -    switch (type) {
> -    case SYS_RES_IOPORT:
> -	rm =&acpi_rman_io;
> -	break;
> -    case SYS_RES_MEMORY:
> -	rm =&acpi_rman_mem;
> -	break;
> -    default:
> -	rm = NULL;
> +	/* Don't reserve system resources. */
> +	if (ACPI_ID_PROBE(dev, children[i], sysres_ids) != NULL)
> +	    continue;
> +
> +	STAILQ_FOREACH(rle, rl, link) {
> +	    /*
> +	     * Don't reserve IRQ resources.  There are many sticky things
> +	     * to get right otherwise (e.g. IRQs for psm, atkbd, and HPET
> +	     * when using legacy routing).
> +	     */
> +	    if (rle->type == SYS_RES_IRQ)
> +		continue;
> +
> +	    /*
> +	     * Try to reserve the resource from our parent.  If this
> +	     * fails because the resource is a system resource, just
> +	     * let it be.  The resource range is already reserved so
> +	     * that other devices will not use it.  If the driver
> +	     * needs to allocate the resource, then
> +	     * acpi_alloc_resource() will sub-alloc from the system
> +	     * resource.
> +	     */
> +	    resource_list_reserve(rl, dev, children[i], rle->type,&rle->rid,
> +		rle->start, rle->end, rle->count, 0);
> +	}
>       }
> -	
> -    ACPI_SERIAL_BEGIN(acpi);
> +    free(children, M_TEMP);
> +    sc->acpi_resources_reserved = 1;
> +}
> +
> +static int
> +acpi_set_resource(device_t dev, device_t child, int type, int rid,
> +    u_long start, u_long count)
> +{
> +    struct acpi_softc *sc = device_get_softc(dev);
> +    struct acpi_device *ad = device_get_ivars(child);
> +    struct resource_list *rl =&ad->ad_rl;
> +    u_long end;
> +
> +    /* Ignore IRQ resources for PCI link devices. */
> +    if (type == SYS_RES_IRQ&&  ACPI_ID_PROBE(dev, child, pcilink_ids) != NULL)
> +	return (0);
> +
> +    /* If the resource is already allocated, fail. */
> +    if (resource_list_busy(rl, type, rid))
> +	return (EBUSY);
> +
> +    /* If the resource is already reserved, release it. */
> +    if (resource_list_reserved(rl, type, rid))
> +	resource_list_unreserve(rl, dev, child, type, rid);
> +
> +    /* Add the resource. */
> +    end = (start + count - 1);
> +    resource_list_add(rl, type, rid, start, end, count);
> +
> +    /* Don't reserve resources until the system resources are allocated. */
> +    if (!sc->acpi_resources_reserved)
> +	return (0);
> +
> +    /* Don't reserve system resources. */
> +    if (ACPI_ID_PROBE(dev, child, sysres_ids) != NULL)
> +	return (0);
>
>       /*
> -     * If this is an allocation of the "default" range for a given RID, and
> -     * we know what the resources for this device are (i.e., they're on the
> -     * child's resource list), use those start/end values.
> -     */
> -    if (bus == device_get_parent(child)&&  start == 0UL&&  end == ~0UL) {
> -	rle = resource_list_find(rl, type, *rid);
> -	if (rle == NULL)
> -	    goto out;
> -	start = rle->start;
> -	end = rle->end;
> -	count = rle->count;
> -    }
> +     * Don't reserve IRQ resources.  There are many sticky things to
> +     * get right otherwise (e.g. IRQs for psm, atkbd, and HPET when
> +     * using legacy routing).
> +     */
> +    if (type == SYS_RES_IRQ)
> +	return (0);
>
>       /*
> -     * If this is an allocation of a specific range, see if we can satisfy
> -     * the request from our system resource regions.  If we can't, pass the
> -     * request up to the parent.
> +     * Reserve the resource.
> +     *
> +     * XXX: Ignores failure for now.  Failure here is probably a
> +     * BIOS/firmware bug?
>        */
> -    if (start + count - 1 == end&&  rm != NULL)
> -	res = rman_reserve_resource(rm, start, end, count, flags&  ~RF_ACTIVE,
> -	    child);
> -    if (res == NULL) {
> -	res = BUS_ALLOC_RESOURCE(device_get_parent(bus), child, type, rid,
> -	    start, end, count, flags);
> -    } else {
> -	rman_set_rid(res, *rid);
> +    resource_list_reserve(rl, dev, child, type,&rid, start, end, count, 0);
> +    return (0);
> +}
>
> -	/* If requested, activate the resource using the parent's method. */
> -	if (flags&  RF_ACTIVE)
> -	    if (bus_activate_resource(child, type, *rid, res) != 0) {
> -		rman_release_resource(res);
> -		res = NULL;
> -		goto out;
> -	    }
> -    }
> +static struct resource *
> +acpi_alloc_resource(device_t bus, device_t child, int type, int *rid,
> +    u_long start, u_long end, u_long count, u_int flags)
> +{
> +    ACPI_RESOURCE ares;
> +    struct acpi_device *ad;
> +    struct resource_list_entry *rle;
> +    struct resource_list *rl;
> +    struct resource *res;
> +    struct rman *rm;
> +    int isdefault = (start == 0UL&&  end == ~0UL);
>
> -    if (res != NULL&&  device_get_parent(child) == bus)
> -	switch (type) {
> -	case SYS_RES_IRQ:
> +    /*
> +     * First attempt at allocating the resource.  For direct children,
> +     * use resource_list_alloc() to handle reserved resources.  For
> +     * other dveices, pass the request up to our parent.
> +     */
> +    if (bus == device_get_parent(child)) {
> +	ad = device_get_ivars(child);
> +	rl =&ad->ad_rl;
> +
> +	/*
> +	 * Simulate the behavior of the ISA bus for direct children
> +	 * devices.  That is, if a non-default range is specified for
> +	 * a resource that doesn't exist, use bus_set_resource() to
> +	 * add the resource before allocating it.  Note that these
> +	 * resources will not be reserved.
> +	 */
> +	if (!isdefault&&  resource_list_find(rl, type, *rid) == NULL)
> +		resource_list_add(rl, type, *rid, start, end, count);
> +	res = resource_list_alloc(rl, bus, child, type, rid, start, end, count,
> +	    flags);
> +	if (res != NULL&&  type == SYS_RES_IRQ) {
>   	    /*
>   	     * Since bus_config_intr() takes immediate effect, we cannot
>   	     * configure the interrupt associated with a device when we
> @@ -1186,11 +1260,59 @@ acpi_alloc_resource(device_t bus, device
>   	     */
>   	    if (ACPI_SUCCESS(acpi_lookup_irq_resource(child, *rid, res,&ares)))
>   		acpi_config_intr(child,&ares);
> -	    break;
>   	}
>
> -out:
> -    ACPI_SERIAL_END(acpi);
> +	/*
> +	 * If this is an allocation of the "default" range for a given
> +	 * RID, fetch the exact bounds for this resource from the
> +	 * resource list entry to try to allocate the range from the
> +	 * system resource regions.
> +	 */
> +	if (res == NULL&&  isdefault) {
> +	    rle = resource_list_find(rl, type, *rid);
> +	    if (rle != NULL) {
> +		start = rle->start;
> +		end = rle->end;
> +		count = rle->count;
> +	    }
> +	}
> +    } else
> +	res = BUS_ALLOC_RESOURCE(device_get_parent(bus), child, type, rid,
> +	    start, end, count, flags);
> +    if (res != NULL || start + count - 1 != end)
> +	return (res);
> +
> +    /*
> +     * If the first attempt failed and this is an allocation of a
> +     * specific range, try to satisfy the request via a suballocation
> +     * from our system resource regions.  Note that we only handle
> +     * memory and I/O port system resources.
> +     */
> +    switch (type) {
> +    case SYS_RES_IOPORT:
> +	rm =&acpi_rman_io;
> +	break;
> +    case SYS_RES_MEMORY:
> +	rm =&acpi_rman_mem;
> +	break;
> +    default:
> +	return (NULL);
> +    }
> +
> +    res = rman_reserve_resource(rm, start, end, count, flags&  ~RF_ACTIVE,
> +	child);
> +    if (res == NULL)
> +	return (NULL);
> +
> +    rman_set_rid(res, *rid);
> +
> +    /* If requested, activate the resource using the parent's method. */
> +    if (flags&  RF_ACTIVE)
> +	if (bus_activate_resource(child, type, *rid, res) != 0) {
> +	    rman_release_resource(res);
> +	    return (NULL);
> +	}
> +
>       return (res);
>   }
>
> @@ -1213,26 +1335,20 @@ acpi_release_resource(device_t bus, devi
>   	rm = NULL;
>       }
>
> -    ACPI_SERIAL_BEGIN(acpi);
> -
>       /*
>        * If this resource belongs to one of our internal managers,
> -     * deactivate it and release it to the local pool.  If it doesn't,
> -     * pass this request up to the parent.
> +     * deactivate it and release it to the local pool.
>        */
>       if (rm != NULL&&  rman_is_region_manager(r, rm)) {
>   	if (rman_get_flags(r)&  RF_ACTIVE) {
>   	    ret = bus_deactivate_resource(child, type, rid, r);
>   	    if (ret != 0)
> -		goto out;
> +		return (ret);
>   	}
> -	ret = rman_release_resource(r);
> -    } else
> -	ret = BUS_RELEASE_RESOURCE(device_get_parent(bus), child, type, rid, r);
> +	return (rman_release_resource(r));
> +    }
>
> -out:
> -    ACPI_SERIAL_END(acpi);
> -    return (ret);
> +    return (bus_generic_rl_release_resource(bus, child, type, rid, r));
>   }
>
>   static void
> @@ -1241,6 +1357,12 @@ acpi_delete_resource(device_t bus, devic
>       struct resource_list *rl;
>
>       rl = acpi_get_rlist(bus, child);
> +    if (resource_list_busy(rl, type, rid)) {
> +	device_printf(bus, "delete_resource: Resource still owned by child"
> +	    " (type=%d, rid=%d)\n", type, rid);
> +	return;
> +    }
> +    resource_list_unreserve(rl, bus, child, type, rid);
>       resource_list_delete(rl, type, rid);
>   }
>
> @@ -1629,6 +1751,9 @@ acpi_probe_children(device_t bus)
>       /* Pre-allocate resources for our rman from any sysresource devices. */
>       acpi_sysres_alloc(bus);
>
> +    /* Reserve resources already allocated to children. */
> +    acpi_reserve_resources(bus);
> +
>       /* Create any static children by calling device identify methods. */
>       ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "device identify routines\n"));
>       bus_generic_probe(bus);
>
> Modified: head/sys/dev/acpica/acpivar.h
> ==============================================================================
> --- head/sys/dev/acpica/acpivar.h	Wed Dec 22 19:57:03 2010	(r216673)
> +++ head/sys/dev/acpica/acpivar.h	Wed Dec 22 20:27:20 2010	(r216674)
> @@ -58,6 +58,7 @@ struct acpi_softc {
>       int			acpi_enabled;
>       int			acpi_sstate;
>       int			acpi_sleep_disabled;
> +    int			acpi_resources_reserved;
>
>       struct sysctl_ctx_list acpi_sysctl_ctx;
>       struct sysctl_oid	*acpi_sysctl_tree;
> _______________________________________________
> svn-src-all at freebsd.org mailing list
> http://lists.freebsd.org/mailman/listinfo/svn-src-all
> To unsubscribe, send any mail to "svn-src-all-unsubscribe at freebsd.org"
>



More information about the svn-src-head mailing list