diff options
-rw-r--r-- | sys/conf/files.sparc64 | 2 | ||||
-rw-r--r-- | sys/dev/le/if_le_lebuffer.c | 408 | ||||
-rw-r--r-- | sys/dev/le/lebuffer_sbus.c | 300 | ||||
-rw-r--r-- | sys/modules/le/Makefile | 6 |
4 files changed, 714 insertions, 2 deletions
diff --git a/sys/conf/files.sparc64 b/sys/conf/files.sparc64 index 981b7dd3e323..a0ea02010889 100644 --- a/sys/conf/files.sparc64 +++ b/sys/conf/files.sparc64 @@ -49,7 +49,9 @@ dev/fb/fb.c optional sc dev/fb/machfb.c optional machfb sc dev/hwpmc/hwpmc_sparc64.c optional hwpmc dev/kbd/kbd.c optional atkbd | sc | ukbd +dev/le/if_le_lebuffer.c optional le sbus dev/le/if_le_ledma.c optional le sbus +dev/le/lebuffer_sbus.c optional le sbus dev/ofw/ofw_bus_if.m standard dev/ofw/ofw_bus_subr.c standard dev/ofw/ofw_console.c optional ofw_console diff --git a/sys/dev/le/if_le_lebuffer.c b/sys/dev/le/if_le_lebuffer.c new file mode 100644 index 000000000000..6c3d3672200e --- /dev/null +++ b/sys/dev/le/if_le_lebuffer.c @@ -0,0 +1,408 @@ +/*- + * Copyright (c) 2006 Marius Strobl <marius@FreeBSD.org> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/bus.h> +#include <sys/endian.h> +#include <sys/kernel.h> +#include <sys/lock.h> +#include <sys/module.h> +#include <sys/mutex.h> +#include <sys/resource.h> +#include <sys/rman.h> +#include <sys/socket.h> + +#include <dev/ofw/ofw_bus.h> + +#include <machine/bus.h> +#include <machine/ofw_machdep.h> +#include <machine/resource.h> + +#include <net/ethernet.h> +#include <net/if.h> +#include <net/if_media.h> + +#include <dev/le/lancereg.h> +#include <dev/le/lancevar.h> +#include <dev/le/am7990reg.h> +#include <dev/le/am7990var.h> + +/* + * LANCE registers + */ +#define LEREG1_RDP 0 /* Register Data port */ +#define LEREG1_RAP 2 /* Register Address port */ + +struct le_lebuffer_softc { + struct am7990_softc sc_am7990; /* glue to MI code */ + + int sc_brid; + struct resource *sc_bres; + bus_space_tag_t sc_buft; + bus_space_handle_t sc_bufh; + + int sc_rrid; + struct resource *sc_rres; + bus_space_tag_t sc_regt; + bus_space_handle_t sc_regh; + + int sc_irid; + struct resource *sc_ires; + void *sc_ih; +}; + +static devclass_t le_lebuffer_devclass; + +static device_probe_t le_lebuffer_probe; +static device_attach_t le_lebuffer_attach; +static device_detach_t le_lebuffer_detach; +static device_resume_t le_buffer_resume; +static device_suspend_t le_buffer_suspend; + +static device_method_t le_lebuffer_methods[] = { + /* Device interface */ + DEVMETHOD(device_probe, le_lebuffer_probe), + DEVMETHOD(device_attach, le_lebuffer_attach), + DEVMETHOD(device_detach, le_lebuffer_detach), + /* We can just use the suspend method here. */ + DEVMETHOD(device_shutdown, le_buffer_suspend), + DEVMETHOD(device_suspend, le_buffer_suspend), + DEVMETHOD(device_resume, le_buffer_resume), + + { 0, 0 } +}; + +DEFINE_CLASS_0(le, le_lebuffer_driver, le_lebuffer_methods, + sizeof(struct le_lebuffer_softc)); +DRIVER_MODULE(le, lebuffer, le_lebuffer_driver, le_lebuffer_devclass, 0, 0); +MODULE_DEPEND(le, ether, 1, 1, 1); + +/* + * Media types supported + */ +static const int le_lebuffer_media[] = { + IFM_MAKEWORD(IFM_ETHER, IFM_10_T, 0, 0) +}; +#define NLEMEDIA \ + (sizeof(le_lebuffer_media) / sizeof(le_lebuffer_media[0])) + +static void le_lebuffer_wrcsr(struct lance_softc *, uint16_t, uint16_t); +static uint16_t le_lebuffer_rdcsr(struct lance_softc *, uint16_t); +static void le_lebuffer_copytodesc(struct lance_softc *, void *, int, int); +static void le_lebuffer_copyfromdesc(struct lance_softc *, void *, int, int); +static void le_lebuffer_copytobuf(struct lance_softc *, void *, int, int); +static void le_lebuffer_copyfrombuf(struct lance_softc *, void *, int, int); +static void le_lebuffer_zerobuf(struct lance_softc *, int, int); + +static void +le_lebuffer_wrcsr(struct lance_softc *sc, uint16_t port, uint16_t val) +{ + struct le_lebuffer_softc *lesc = (struct le_lebuffer_softc *)sc; + + bus_space_write_2(lesc->sc_regt, lesc->sc_regh, LEREG1_RAP, port); + bus_space_barrier(lesc->sc_regt, lesc->sc_regh, LEREG1_RAP, 2, + BUS_SPACE_BARRIER_WRITE); + bus_space_write_2(lesc->sc_regt, lesc->sc_regh, LEREG1_RDP, val); +} + +static uint16_t +le_lebuffer_rdcsr(struct lance_softc *sc, uint16_t port) +{ + struct le_lebuffer_softc *lesc = (struct le_lebuffer_softc *)sc; + + bus_space_write_2(lesc->sc_regt, lesc->sc_regh, LEREG1_RAP, port); + bus_space_barrier(lesc->sc_regt, lesc->sc_regh, LEREG1_RAP, 2, + BUS_SPACE_BARRIER_WRITE); + return (bus_space_read_2(lesc->sc_regt, lesc->sc_regh, LEREG1_RDP)); +} + +/* + * It turns out that using bus_space(9) to access the buffers and the + * descriptors yields way more throughput than accessing them via the + * KVA returned by rman_get_virtual(9). The descriptor rings can be + * accessed using 8-bit up to 64-bit operations while the buffers can + * be only accessed using 8-bit and 16-bit operations. + * NB: For whatever reason setting LE_C3_BSWP has no effect with at + * least the 501-2981 (although their 'busmaster-regval' property + * indicates to set LE_C3_BSWP also for these cards), so we need + * to manually byte swap access to the buffers, i.e. the accesses + * going through the RX/TX FIFOs. + */ + +static void +le_lebuffer_copytodesc(struct lance_softc *sc, void *fromv, int off, int len) +{ + struct le_lebuffer_softc *lesc = (struct le_lebuffer_softc *)sc; + caddr_t from = fromv; + + for (; len >= 8; len -= 8, off += 8, from += 8) + bus_space_write_8(lesc->sc_buft, lesc->sc_bufh, off, + be64dec(from)); + for (; len >= 4; len -= 4, off += 4, from += 4) + bus_space_write_4(lesc->sc_buft, lesc->sc_bufh, off, + be32dec(from)); + for (; len >= 2; len -= 2, off += 2, from += 2) + bus_space_write_2(lesc->sc_buft, lesc->sc_bufh, off, + be16dec(from)); + if (len == 1) + bus_space_write_1(lesc->sc_buft, lesc->sc_bufh, off, + *from); +} + +static void +le_lebuffer_copyfromdesc(struct lance_softc *sc, void *tov, int off, int len) +{ + struct le_lebuffer_softc *lesc = (struct le_lebuffer_softc *)sc; + caddr_t to = tov; + + for (; len >= 8; len -= 8, off += 8, to += 8) + be64enc(to, + bus_space_read_8(lesc->sc_buft, lesc->sc_bufh, off)); + for (; len >= 4; len -= 4, off += 4, to += 4) + be32enc(to, + bus_space_read_4(lesc->sc_buft, lesc->sc_bufh, off)); + for (; len >= 2; len -= 2, off += 2, to += 2) + be16enc(to, + bus_space_read_2(lesc->sc_buft, lesc->sc_bufh, off)); + if (len == 1) + *to = + bus_space_read_1(lesc->sc_buft, lesc->sc_bufh, off); +} + +static void +le_lebuffer_copytobuf(struct lance_softc *sc, void *fromv, int off, int len) +{ + struct le_lebuffer_softc *lesc = (struct le_lebuffer_softc *)sc; + caddr_t from = fromv; + + for (; len >= 2; len -= 2, off += 2, from += 2) + bus_space_write_2(lesc->sc_buft, lesc->sc_bufh, off, + le16dec(from)); + if (len == 1) + bus_space_write_1(lesc->sc_buft, lesc->sc_bufh, off + 1, + *from); +} + +static void +le_lebuffer_copyfrombuf(struct lance_softc *sc, void *tov, int off, int len) +{ + struct le_lebuffer_softc *lesc = (struct le_lebuffer_softc *)sc; + caddr_t to = tov; + + for (; len >= 2; len -= 2, off += 2, to += 2) + le16enc(to, + bus_space_read_2(lesc->sc_buft, lesc->sc_bufh, off)); + if (len == 1) + *to = + bus_space_read_1(lesc->sc_buft, lesc->sc_bufh, off + 1); +} + +static void +le_lebuffer_zerobuf(struct lance_softc *sc, int off, int len) +{ + struct le_lebuffer_softc *lesc = (struct le_lebuffer_softc *)sc; + + for (; len >= 2; len -= 2, off += 2) + bus_space_write_2(lesc->sc_buft, lesc->sc_bufh, off, 0); + if (len == 1) + bus_space_write_1(lesc->sc_buft, lesc->sc_bufh, off + 1, 0); +} + +static int +le_lebuffer_probe(device_t dev) +{ + + if (strcmp(ofw_bus_get_name(dev), "le") == 0) { + device_set_desc(dev, "LANCE Ethernet"); + return (BUS_PROBE_DEFAULT); + } + return (ENXIO); +} + +static int +le_lebuffer_attach(device_t dev) +{ + struct le_lebuffer_softc *lesc; + struct lance_softc *sc; + int error; + + lesc = device_get_softc(dev); + sc = &lesc->sc_am7990.lsc; + + LE_LOCK_INIT(sc, device_get_nameunit(dev)); + + /* + * The "register space" of the parent is just a buffer where the + * the LANCE descriptor rings and the RX/TX buffers can be stored. + */ + lesc->sc_brid = 0; + lesc->sc_bres = bus_alloc_resource_any(device_get_parent(dev), + SYS_RES_MEMORY, &lesc->sc_brid, RF_ACTIVE); + if (lesc->sc_bres == NULL) { + device_printf(dev, "cannot allocate LANCE buffer\n"); + error = ENXIO; + goto fail_mtx; + } + lesc->sc_buft = rman_get_bustag(lesc->sc_bres); + lesc->sc_bufh = rman_get_bushandle(lesc->sc_bres); + + /* Allocate LANCE registers. */ + lesc->sc_rrid = 0; + lesc->sc_rres = bus_alloc_resource_any(dev, SYS_RES_MEMORY, + &lesc->sc_rrid, RF_ACTIVE); + if (lesc->sc_rres == NULL) { + device_printf(dev, "cannot allocate LANCE registers\n"); + error = ENXIO; + goto fail_bres; + } + lesc->sc_regt = rman_get_bustag(lesc->sc_rres); + lesc->sc_regh = rman_get_bushandle(lesc->sc_rres); + + /* Allocate LANCE interrupt. */ + lesc->sc_irid = 0; + if ((lesc->sc_ires = bus_alloc_resource_any(dev, SYS_RES_IRQ, + &lesc->sc_irid, RF_SHAREABLE | RF_ACTIVE)) == NULL) { + device_printf(dev, "cannot allocate interrupt\n"); + error = ENXIO; + goto fail_rres; + } + + /* + * LANCE view is offset by buffer location. + * Note that we don't use sc->sc_mem. + */ + sc->sc_addr = 0; + sc->sc_memsize = rman_get_size(lesc->sc_bres); + sc->sc_flags = 0; + + /* That old black magic... */ + if (OF_getprop(ofw_bus_get_node(dev), "busmaster-regval", + &sc->sc_conf3, sizeof(sc->sc_conf3)) == -1) + sc->sc_conf3 = LE_C3_ACON | LE_C3_BCON; + /* + * Make sure LE_C3_BSWP is cleared so that for cards where + * that flag actually works le_lebuffer_copy{from,to}buf() + * don't fail... + */ + sc->sc_conf3 &= ~LE_C3_BSWP; + + OF_getetheraddr(dev, sc->sc_enaddr); + + sc->sc_copytodesc = le_lebuffer_copytodesc; + sc->sc_copyfromdesc = le_lebuffer_copyfromdesc; + sc->sc_copytobuf = le_lebuffer_copytobuf; + sc->sc_copyfrombuf = le_lebuffer_copyfrombuf; + sc->sc_zerobuf = le_lebuffer_zerobuf; + + sc->sc_rdcsr = le_lebuffer_rdcsr; + sc->sc_wrcsr = le_lebuffer_wrcsr; + sc->sc_hwreset = NULL; + sc->sc_hwinit = NULL; + sc->sc_hwintr = NULL; + sc->sc_nocarrier = NULL; + sc->sc_mediachange = NULL; + sc->sc_mediastatus = NULL; + sc->sc_supmedia = le_lebuffer_media; + sc->sc_nsupmedia = NLEMEDIA; + sc->sc_defaultmedia = le_lebuffer_media[0]; + + error = am7990_config(&lesc->sc_am7990, device_get_name(dev), + device_get_unit(dev)); + if (error != 0) { + device_printf(dev, "cannot attach Am7990\n"); + goto fail_ires; + } + + error = bus_setup_intr(dev, lesc->sc_ires, INTR_TYPE_NET | INTR_MPSAFE, + am7990_intr, sc, &lesc->sc_ih); + if (error != 0) { + device_printf(dev, "cannot set up interrupt\n"); + goto fail_am7990; + } + + return (0); + + fail_am7990: + am7990_detach(&lesc->sc_am7990); + fail_ires: + bus_release_resource(dev, SYS_RES_IRQ, lesc->sc_irid, lesc->sc_ires); + fail_rres: + bus_release_resource(dev, SYS_RES_MEMORY, lesc->sc_rrid, lesc->sc_rres); + fail_bres: + bus_release_resource(device_get_parent(dev), SYS_RES_MEMORY, + lesc->sc_brid, lesc->sc_bres); + fail_mtx: + LE_LOCK_DESTROY(sc); + return (error); +} + +static int +le_lebuffer_detach(device_t dev) +{ + struct le_lebuffer_softc *lesc; + struct lance_softc *sc; + + lesc = device_get_softc(dev); + sc = &lesc->sc_am7990.lsc; + + bus_teardown_intr(dev, lesc->sc_ires, lesc->sc_ih); + am7990_detach(&lesc->sc_am7990); + bus_release_resource(dev, SYS_RES_IRQ, lesc->sc_irid, lesc->sc_ires); + bus_release_resource(dev, SYS_RES_MEMORY, lesc->sc_rrid, lesc->sc_rres); + bus_release_resource(device_get_parent(dev), SYS_RES_MEMORY, + lesc->sc_brid, lesc->sc_bres); + LE_LOCK_DESTROY(sc); + + return (0); +} + +static int +le_buffer_suspend(device_t dev) +{ + struct le_lebuffer_softc *lesc; + + lesc = device_get_softc(dev); + + lance_suspend(&lesc->sc_am7990.lsc); + + return (0); +} + +static int +le_buffer_resume(device_t dev) +{ + struct le_lebuffer_softc *lesc; + + lesc = device_get_softc(dev); + + lance_resume(&lesc->sc_am7990.lsc); + + return (0); +} diff --git a/sys/dev/le/lebuffer_sbus.c b/sys/dev/le/lebuffer_sbus.c new file mode 100644 index 000000000000..71a19faef7fd --- /dev/null +++ b/sys/dev/le/lebuffer_sbus.c @@ -0,0 +1,300 @@ +/*- + * Copyright (c) 2006 Marius Strobl <marius@FreeBSD.org> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/bus.h> +#include <sys/kernel.h> +#include <sys/module.h> +#include <sys/resource.h> +#include <sys/rman.h> + +#include <dev/ofw/ofw_bus.h> +#include <dev/ofw/ofw_bus_subr.h> +#include <dev/ofw/openfirm.h> + +#include <machine/bus.h> +#include <machine/bus_common.h> +#include <machine/resource.h> + +#include <sparc64/sbus/ofw_sbus.h> +#include <sparc64/sbus/sbusreg.h> +#include <sparc64/sbus/sbusvar.h> + +struct lebuffer_devinfo { + struct ofw_bus_devinfo ldi_obdinfo; + struct resource_list ldi_rl; +}; + +static devclass_t lebuffer_devclass; + +static device_probe_t lebuffer_probe; +static device_attach_t lebuffer_attach; +static device_detach_t lebuffer_detach; +static bus_print_child_t lebuffer_print_child; +static bus_probe_nomatch_t lebuffer_probe_nomatch; +static bus_get_resource_list_t lebuffer_get_resource_list; +static ofw_bus_get_devinfo_t lebuffer_get_devinfo; + +static struct lebuffer_devinfo *lebuffer_setup_dinfo(device_t, phandle_t); +static void lebuffer_destroy_dinfo(struct lebuffer_devinfo *); +static int lebuffer_print_res(struct lebuffer_devinfo *); + +static device_method_t lebuffer_methods[] = { + /* Device interface */ + DEVMETHOD(device_probe, lebuffer_probe), + DEVMETHOD(device_attach, lebuffer_attach), + DEVMETHOD(device_detach, lebuffer_detach), + DEVMETHOD(device_shutdown, bus_generic_shutdown), + DEVMETHOD(device_suspend, bus_generic_suspend), + DEVMETHOD(device_resume, bus_generic_resume), + + /* Bus interface */ + DEVMETHOD(bus_print_child, lebuffer_print_child), + DEVMETHOD(bus_probe_nomatch, lebuffer_probe_nomatch), + DEVMETHOD(bus_setup_intr, bus_generic_setup_intr), + DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr), + DEVMETHOD(bus_alloc_resource, bus_generic_rl_alloc_resource), + DEVMETHOD(bus_release_resource, bus_generic_rl_release_resource), + DEVMETHOD(bus_activate_resource, bus_generic_activate_resource), + DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource), + DEVMETHOD(bus_get_resource_list, lebuffer_get_resource_list), + DEVMETHOD(bus_get_resource, bus_generic_rl_get_resource), + + /* ofw_bus interface */ + DEVMETHOD(ofw_bus_get_devinfo, lebuffer_get_devinfo), + DEVMETHOD(ofw_bus_get_compat, ofw_bus_gen_get_compat), + DEVMETHOD(ofw_bus_get_model, ofw_bus_gen_get_model), + DEVMETHOD(ofw_bus_get_name, ofw_bus_gen_get_name), + DEVMETHOD(ofw_bus_get_node, ofw_bus_gen_get_node), + DEVMETHOD(ofw_bus_get_type, ofw_bus_gen_get_type), + + { 0, 0 } +}; + +DEFINE_CLASS_0(lebuffer, lebuffer_driver, lebuffer_methods, 1); +DRIVER_MODULE(lebuffer, sbus, lebuffer_driver, lebuffer_devclass, 0, 0); + +static int +lebuffer_probe(device_t dev) +{ + const char *name; + + name = ofw_bus_get_name(dev); + if (strcmp(name, "lebuffer") == 0) { + device_set_desc_copy(dev, name); + return (0); + } + return (ENXIO); +} + +static int +lebuffer_attach(device_t dev) +{ + struct lebuffer_devinfo *ldi; + device_t cdev; + phandle_t child; + int children; + + children = 0; + for (child = OF_child(ofw_bus_get_node(dev)); child != 0; + child = OF_peer(child)) { + if ((ldi = lebuffer_setup_dinfo(dev, child)) == NULL) + continue; + if (children != 0) { + device_printf(dev, + "<%s>: only one child per buffer supported\n", + ldi->ldi_obdinfo.obd_name); + lebuffer_destroy_dinfo(ldi); + continue; + } + if ((cdev = device_add_child(dev, NULL, -1)) == NULL) { + device_printf(dev, "<%s>: device_add_child failed\n", + ldi->ldi_obdinfo.obd_name); + lebuffer_destroy_dinfo(ldi); + continue; + } + device_set_ivars(cdev, ldi); + children++; + } + return (bus_generic_attach(dev)); +} + +static int +lebuffer_detach(device_t dev) +{ + device_t *children; + int i, nchildren; + + bus_generic_detach(dev); + if (device_get_children(dev, &children, &nchildren) == 0) { + for (i = 0; i < nchildren; i++) { + lebuffer_destroy_dinfo(device_get_ivars(children[i])); + device_delete_child(dev, children[i]); + } + free(children, M_TEMP); + } + return (0); +} + +static struct lebuffer_devinfo * +lebuffer_setup_dinfo(device_t dev, phandle_t node) +{ + struct lebuffer_devinfo *ldi; + struct sbus_regs *reg; + uint32_t base, iv, *intr; + int i, nreg, nintr, slot, rslot; + + ldi = malloc(sizeof(*ldi), M_DEVBUF, M_WAITOK | M_ZERO); + if (ofw_bus_gen_setup_devinfo(&ldi->ldi_obdinfo, node) != 0) { + free(ldi, M_DEVBUF); + return (NULL); + } + resource_list_init(&ldi->ldi_rl); + slot = -1; + nreg = OF_getprop_alloc(node, "reg", sizeof(*reg), (void **)®); + if (nreg == -1) { + device_printf(dev, "<%s>: incomplete\n", + ldi->ldi_obdinfo.obd_name); + goto fail; + } + for (i = 0; i < nreg; i++) { + base = reg[i].sbr_offset; + if (SBUS_ABS(base)) { + rslot = SBUS_ABS_TO_SLOT(base); + base = SBUS_ABS_TO_OFFSET(base); + } else + rslot = reg[i].sbr_slot; + if (slot != -1 && slot != rslot) { + device_printf(dev, "<%s>: multiple slots\n", + ldi->ldi_obdinfo.obd_name); + free(reg, M_OFWPROP); + goto fail; + } + slot = rslot; + + resource_list_add(&ldi->ldi_rl, SYS_RES_MEMORY, i, base, + base + reg[i].sbr_size, reg[i].sbr_size); + } + free(reg, M_OFWPROP); + if (slot != sbus_get_slot(dev)) { + device_printf(dev, "<%s>: parent and child slot do not match\n", + ldi->ldi_obdinfo.obd_name); + goto fail; + } + + /* + * The `interrupts' property contains the SBus interrupt level. + */ + nintr = OF_getprop_alloc(node, "interrupts", sizeof(*intr), + (void **)&intr); + if (nintr != -1) { + for (i = 0; i < nintr; i++) { + iv = intr[i]; + /* + * SBus card devices need the slot number encoded into + * the vector as this is generally not done. + */ + if ((iv & INTMAP_OBIO_MASK) == 0) + iv |= slot << 3; + /* Set the IGN as appropriate. */ + iv |= sbus_get_ign(dev) << INTMAP_IGN_SHIFT; + resource_list_add(&ldi->ldi_rl, SYS_RES_IRQ, i, + iv, iv, 1); + } + free(intr, M_OFWPROP); + } + return (ldi); + + fail: + lebuffer_destroy_dinfo(ldi); + return (NULL); +} + +static void +lebuffer_destroy_dinfo(struct lebuffer_devinfo *dinfo) +{ + + resource_list_free(&dinfo->ldi_rl); + ofw_bus_gen_destroy_devinfo(&dinfo->ldi_obdinfo); + free(dinfo, M_DEVBUF); +} + +static int +lebuffer_print_child(device_t dev, device_t child) +{ + int rv; + + rv = bus_print_child_header(dev, child); + rv += lebuffer_print_res(device_get_ivars(child)); + rv += bus_print_child_footer(dev, child); + return (rv); +} + +static void +lebuffer_probe_nomatch(device_t dev, device_t child) +{ + const char *type; + + device_printf(dev, "<%s>", ofw_bus_get_name(child)); + lebuffer_print_res(device_get_ivars(child)); + type = ofw_bus_get_type(child); + printf(" type %s (no driver attached)\n", + type != NULL ? type : "unknown"); +} + +static struct resource_list * +lebuffer_get_resource_list(device_t dev, device_t child) +{ + struct lebuffer_devinfo *ldi; + + ldi = device_get_ivars(child); + return (&ldi->ldi_rl); +} + +static const struct ofw_bus_devinfo * +lebuffer_get_devinfo(device_t bus, device_t child) +{ + struct lebuffer_devinfo *ldi; + + ldi = device_get_ivars(child); + return (&ldi->ldi_obdinfo); +} + +static int +lebuffer_print_res(struct lebuffer_devinfo *ldi) +{ + int rv; + + rv = 0; + rv += resource_list_print_type(&ldi->ldi_rl, "mem", SYS_RES_MEMORY, + "%#lx"); + rv += resource_list_print_type(&ldi->ldi_rl, "irq", SYS_RES_IRQ, "%ld"); + return (rv); +} diff --git a/sys/modules/le/Makefile b/sys/modules/le/Makefile index 0d484ec5f7b3..d3101e175152 100644 --- a/sys/modules/le/Makefile +++ b/sys/modules/le/Makefile @@ -3,8 +3,8 @@ .PATH: ${.CURDIR}/../../dev/le KMOD= if_le -SRCS= am7990.c am79900.c ${if_le_cbus} ${if_le_isa} ${if_le_ledma} -SRCS+= if_le_pci.c lance.c +SRCS= am7990.c am79900.c ${if_le_cbus} ${if_le_isa} ${if_le_lebuffer} +SRCS+= ${if_le_ledma} if_le_pci.c lance.c ${lebuffer_sbus} SRCS+= bus_if.h device_if.h ${isa_if} ${ofw_bus_if} pci_if.h .if ${MACHINE_ARCH} == "i386" @@ -17,7 +17,9 @@ isa_if= isa_if.h .endif .if ${MACHINE_ARCH} == "sparc64" +if_le_lebuffer= if_le_lebuffer.c if_le_ledma= if_le_ledma.c +lebuffer_sbus= lebuffer_sbus.c ofw_bus_if= ofw_bus_if.h .endif |