Skip site navigation (1)Skip section navigation (2)
Date:      Sun, 9 May 2004 17:14:44 +0200
From:      Joerg Wunsch <j@ida.interface-business.de>
To:        sparc64@freebsd.org
Subject:   ebus resource allocation error?
Message-ID:  <20040509171444.B63877@ida.interface-business.de>

next in thread | raw e-mail | index | archive | help

--Q68bSM7Ycu6FN28Q
Content-Type: text/plain; charset=iso-8859-1
Content-Disposition: inline
Content-Transfer-Encoding: 8bit

I'm currently investigating the chances of writing a driver for the
SUNW,envctrl device of my E450.  Supposedly, this is an I²C bus, so
it's my hope to eventually setup the driver as a glue interface
between the Sun hardware and iicbus/smbus.

This hardware has the curious (for me at least) situation that it
gets two IRQs assigned:

SUNW,envctrl0: <EBus SUNW,envctrl> addr 0x1400600000-0x1400600003 irq 2021,2024 on ebus0

However, when trying to bus_alloc_resource the second IRQ, I always
get a resource allocation error.  Since the code used for resource
allocation is basically the same as I've successfully been using to
allocate multiple IO port ranges in my auxio driver, I rather suspect
a problem in the ebus code itself.

Below are the current probe messages, attached is the source code.
(Please do not redistribute by now, it's really only a stub driver.)

SUNW,envctrl0: <EBus SUNW,envctrl> addr 0x1400600000-0x1400600003 irq 2021,2024 on ebus0
SUNW,envctrl0: Got IRQ rid 0, start 0x7e8, count 0x1
SUNW,envctrl0: Got IRQ rid 1, start 0x7e5, count 0x1
SUNW,envctrl0: could not allocate resources: 2nd IRQ
device_probe_and_attach: SUNW,envctrl0 attach returned 6

-- 
J"org Wunsch					       Unix support engineer
joerg_wunsch@interface-systems.de        http://www.interface-systems.de/~j/

--Q68bSM7Ycu6FN28Q
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment; filename="envctrl.c"

/*
 * Copyright 2004, Joerg Wunsch
 */
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/bus.h>
#include <sys/conf.h>
#include <sys/kernel.h>
#include <sys/malloc.h>
#include <sys/resource.h>
#include <sys/uio.h>

#include <machine/bus.h>
#include <machine/resource.h>

#include <sys/rman.h>

#include <dev/ofw/openfirm.h>

#include <sparc64/ebus/ebusvar.h>

static int envctrl_probe(device_t);
static int envctrl_attach(device_t);
static int envctrl_detach(device_t);

static device_method_t envctrl_methods[] = {
	/* Device interface */
	DEVMETHOD(device_probe,		envctrl_probe),
	DEVMETHOD(device_attach,	envctrl_attach),
	DEVMETHOD(device_detach,	envctrl_detach),

	{ 0, 0 }
};

struct envctrl_softc {
	struct	resource *iores;
	struct	resource *intres[2];
	dev_t	devfs_cookie;
	device_t dev;
	void	*intr_cookie[2];
};

static devclass_t envctrl_devclass;

static driver_t envctrl_driver = {
	"SUNW,envctrl",
	envctrl_methods,
	sizeof(struct envctrl_softc),
};

DRIVER_MODULE(envctrl, ebus, envctrl_driver, envctrl_devclass, 0, 0);

static	d_open_t	envctrl_open;
static	d_close_t	envctrl_close;
static	d_read_t	envctrl_read;
static	d_write_t	envctrl_write;
static	d_ioctl_t	envctrl_ioctl;
static	driver_intr_t	envctrl_intr1;
static	driver_intr_t	envctrl_intr2;


static struct cdevsw envctrl_cdevsw = {
	.d_version =	D_VERSION,
	.d_open =	envctrl_open,
	.d_close =	envctrl_close,
	.d_read =	envctrl_read,
	.d_write =	envctrl_write,
	.d_ioctl =	envctrl_ioctl,
	.d_name =	"SUNW,envctrl",
};


static int
envctrl_probe(device_t dev)
{

	if (strcmp("SUNW,envctrl", ebus_get_name(dev)) == 0) {
		device_set_desc(dev, "EBus SUNW,envctrl");
		return (0);
	}
	return (ENXIO);
}

static int
envctrl_attach(device_t dev)
{
	struct envctrl_softc *sc;
	struct resource *res;
	const char *errmsg;
	int rid, rv, i;
	u_long start, count;

	sc = device_get_softc(dev);

	rid = 0;
	res = bus_alloc_resource_any(dev, SYS_RES_IOPORT, &rid, RF_ACTIVE);
	if (res == NULL) {
		errmsg = "IO port";
		goto allocfail;
	}
	sc->iores = res;
	for (i = 0; i < 2; i++) {
		if (bus_get_resource(dev, SYS_RES_IRQ, i, &start, &count) != 0)
			continue;
		rid = i;
		if (bootverbose)
			device_printf(dev,
				      "Got IRQ rid %d, start %#lx, count %#lx\n",
				      i, start, count);
		res = bus_alloc_resource(dev, SYS_RES_IRQ, &rid,
					 start, start + count - 1,
					 count, RF_ACTIVE);
		if (res == NULL) {
			errmsg = i == 0? "1st IRQ": "2nd IRQ";
			goto allocfail;
		}
		sc->intres[i] = res;
	}
	rv = BUS_SETUP_INTR(device_get_parent(dev), dev, sc->intres[0],
			    INTR_TYPE_MISC /* | INTR_ENTROPY */,
			    envctrl_intr1, sc, sc->intr_cookie + 0);
	if (rv) {
		errmsg = "1st IRQ";
		goto irqfail;
	}
	rv = BUS_SETUP_INTR(device_get_parent(dev), dev, sc->intres[1],
			    INTR_TYPE_MISC /* | INTR_ENTROPY */,
			    envctrl_intr2, sc, sc->intr_cookie + 1);
	if (rv) {
		errmsg = "1st IRQ";
		goto irqfail;
	}

	sc->devfs_cookie = make_dev(&envctrl_cdevsw, 0, UID_ROOT, GID_WHEEL,
				    0600, "envctrl");
	sc->dev = dev;

	return (0);

 allocfail:
	device_printf(dev, "could not allocate resources: %s\n", errmsg);
	return (ENXIO);
 irqfail:
	device_printf(dev, "could not setup %s\n", errmsg);
	return (ENXIO);
}

static int
envctrl_detach(device_t dev)
{
	struct envctrl_softc *sc;

	sc = device_get_softc(dev);

	BUS_TEARDOWN_INTR(device_get_parent(dev), dev, sc->intres[0],
                          sc->intr_cookie[0]);
	BUS_TEARDOWN_INTR(device_get_parent(dev), dev, sc->intres[1],
                          sc->intr_cookie[1]);
	bus_deactivate_resource(dev, SYS_RES_IRQ, 0, sc->intres[0]);
	bus_release_resource(dev, SYS_RES_IRQ, 0, sc->intres[0]);
	bus_deactivate_resource(dev, SYS_RES_IRQ, 1, sc->intres[1]);
	bus_release_resource(dev, SYS_RES_IRQ, 1, sc->intres[1]);
	bus_deactivate_resource(dev, SYS_RES_IOPORT, 0, sc->iores);
	bus_release_resource(dev, SYS_RES_IOPORT, 0, sc->iores);

	destroy_dev(sc->devfs_cookie);

	return (0);
}

static int
envctrl_open(dev_t dev, int oflags, int devtype, struct thread *td)
{

	return (0);
}

static int
envctrl_close(dev_t dev, int fflag, int devtype, struct thread *td)
{

	return (0);
}

static int
envctrl_read(dev_t dev, struct uio *uio, int ioflag)
{
	struct envctrl_softc *sc;
	uint32_t buf;
	int rv;

	if (uio->uio_offset != 0)
		return (0);
	if (uio->uio_resid < sizeof(uint32_t))
		return (EINVAL);

	sc = devclass_get_softc(envctrl_devclass, 0);

	buf = bus_space_read_4(sc->iores->r_bustag, sc->iores->r_bushandle, 0);
	rv = uiomove(&buf, sizeof(uint32_t), uio);

	return (rv);
}

static int
envctrl_write(dev_t dev, struct uio *uio, int ioflag)
{
	struct envctrl_softc *sc;
	uint32_t buf;
	int rv;

	if (uio->uio_offset != 0)
		return (0);
	if (uio->uio_resid < sizeof(uint32_t))
		return (EINVAL);

	sc = devclass_get_softc(envctrl_devclass, 0);

	if ((rv = uiomove(&buf, sizeof(uint32_t), uio)) != 0)
		return (rv);
	bus_space_write_4(sc->iores->r_bustag, sc->iores->r_bushandle, 0, buf);

	return (0);
}

static int
envctrl_ioctl(dev_t dev, u_long cmd, caddr_t data,
	    int fflag, struct thread *td)
{

	return (ENXIO);
}

static void
envctrl_intr1(void *arg)
{
	struct envctrl_softc *sc = (struct envctrl_softc *)arg;

	device_printf(sc->dev, "1st IRQ triggered\n");
}

static void
envctrl_intr2(void *arg)
{
	struct envctrl_softc *sc = (struct envctrl_softc *)arg;

	device_printf(sc->dev, "2nd IRQ triggered\n");
}

--Q68bSM7Ycu6FN28Q--



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20040509171444.B63877>