Exemple #1
0
static int
thunder_pem_get_id(device_t pci, device_t child, enum pci_id_type type,
    uintptr_t *id)
{
	int bsf;
	int pem;

	if (type != PCI_ID_MSI)
		return (pcib_get_id(pci, child, type, id));

	bsf = pci_get_rid(child);

	/* PEM (PCIe MAC/root complex) number is equal to domain */
	pem = pci_get_domain(child);

	/*
	 * Set appropriate device ID (passed by the HW along with
	 * the transaction to memory) for different root complex
	 * numbers using hard-coded domain portion for each group.
	 */
	if (pem < 3)
		*id = (0x1 << PCI_RID_DOMAIN_SHIFT) | bsf;
	else if (pem < 6)
		*id = (0x3 << PCI_RID_DOMAIN_SHIFT) | bsf;
	else if (pem < 9)
		*id = (0x9 << PCI_RID_DOMAIN_SHIFT) | bsf;
	else if (pem < 12)
		*id = (0xB << PCI_RID_DOMAIN_SHIFT) | bsf;
	else
		return (ENXIO);

	return (0);
}
Exemple #2
0
static void
sfxge_mcdi_logger(void *arg, efx_log_msg_t type,
		  void *header, size_t header_size,
		  void *data, size_t data_size)
{
	struct sfxge_softc *sc = (struct sfxge_softc *)arg;
	char buffer[SFXGE_MCDI_LOG_BUF_SIZE];
	size_t pfxsize;
	size_t start;

	if (!sc->mcdi_logging)
		return;

	pfxsize = snprintf(buffer, sizeof(buffer),
			   "sfc %04x:%02x:%02x.%02x %s MCDI RPC %s:",
			   pci_get_domain(sc->dev),
			   pci_get_bus(sc->dev),
			   pci_get_slot(sc->dev),
			   pci_get_function(sc->dev),
			   device_get_nameunit(sc->dev),
			   type == EFX_LOG_MCDI_REQUEST ? "REQ" :
			   type == EFX_LOG_MCDI_RESPONSE ? "RESP" : "???");
	start = sfxge_mcdi_do_log(buffer, header, header_size,
				  pfxsize, pfxsize);
	start = sfxge_mcdi_do_log(buffer, data, data_size, pfxsize, start);
	if (start != pfxsize) {
		buffer[start] = '\0';
		printf("%s\n", buffer);
	}
}
Exemple #3
0
/*
 * Return a pointer to a pretty name for a PCI device.  If the device
 * has a driver attached, the device's name is used, otherwise a name
 * is generated from the device's PCI address.
 */
const char *
pcib_child_name(device_t child)
{
	static char buf[64];

	if (device_get_nameunit(child) != NULL)
		return (device_get_nameunit(child));
	snprintf(buf, sizeof(buf), "pci%d:%d:%d:%d", pci_get_domain(child),
	    pci_get_bus(child), pci_get_slot(child), pci_get_function(child));
	return (buf);
}
Exemple #4
0
static int
t4iov_attach(device_t dev)
{
	struct t4iov_softc *sc;

	sc = device_get_softc(dev);
	sc->sc_dev = dev;

	sc->sc_main = pci_find_dbsf(pci_get_domain(dev), pci_get_bus(dev),
	    pci_get_slot(dev), 4);
	if (T4_IS_MAIN_READY(sc->sc_main) == 0)
		return (t4iov_attach_child(dev));
	return (0);
}
Exemple #5
0
static bool radeon_atrm_get_bios(struct radeon_device *rdev)
{
	int ret;
	int size = 256 * 1024;
	int i;
	device_t dev;
	ACPI_HANDLE dhandle, atrm_handle;
	ACPI_STATUS status;
	bool found = false;

	DRM_INFO("%s: ===> Try ATRM...\n", __func__);

	/* ATRM is for the discrete card only */
	if (rdev->flags & RADEON_IS_IGP) {
		DRM_INFO("%s: IGP card detected, skipping this method...\n",
		    __func__);
		return false;
	}

#ifdef FREEBSD_WIP
	while ((pdev = pci_get_class(PCI_CLASS_DISPLAY_VGA << 8, pdev)) != NULL) {
#endif /* FREEBSD_WIP */
	if ((dev = pci_find_class(PCIC_DISPLAY, PCIS_DISPLAY_VGA)) != NULL) {
		DRM_INFO("%s: pci_find_class() found: %d:%d:%d:%d, vendor=%04x, device=%04x\n",
		    __func__,
		    pci_get_domain(dev),
		    pci_get_bus(dev),
		    pci_get_slot(dev),
		    pci_get_function(dev),
		    pci_get_vendor(dev),
		    pci_get_device(dev));
		DRM_INFO("%s: Get ACPI device handle\n", __func__);
		dhandle = acpi_get_handle(dev);
#ifdef FREEBSD_WIP
		if (!dhandle)
			continue;
#endif /* FREEBSD_WIP */
		if (!dhandle)
			return false;

		DRM_INFO("%s: Get ACPI handle for \"ATRM\"\n", __func__);
		status = AcpiGetHandle(dhandle, "ATRM", &atrm_handle);
		if (!ACPI_FAILURE(status)) {
			found = true;
#ifdef FREEBSD_WIP
			break;
#endif /* FREEBSD_WIP */
		} else {
			DRM_INFO("%s: Failed to get \"ATRM\" handle: %s\n",
			    __func__, AcpiFormatException(status));
		}
	}

	if (!found)
		return false;

	rdev->bios = malloc(size, DRM_MEM_DRIVER, M_NOWAIT);
	if (!rdev->bios) {
		DRM_ERROR("Unable to allocate bios\n");
		return false;
	}

	for (i = 0; i < size / ATRM_BIOS_PAGE; i++) {
		DRM_INFO("%s: Call radeon_atrm_call()\n", __func__);
		ret = radeon_atrm_call(atrm_handle,
				       rdev->bios,
				       (i * ATRM_BIOS_PAGE),
				       ATRM_BIOS_PAGE);
		if (ret < ATRM_BIOS_PAGE)
			break;
	}

	if (i == 0 || rdev->bios[0] != 0x55 || rdev->bios[1] != 0xaa) {
		if (i == 0) {
			DRM_INFO("%s: Incorrect BIOS size\n", __func__);
		} else {
			DRM_INFO("%s: Incorrect BIOS signature: 0x%02X%02X\n",
			    __func__, rdev->bios[0], rdev->bios[1]);
		}
		free(rdev->bios, DRM_MEM_DRIVER);
		return false;
	}
	return true;
}
#else
static inline bool radeon_atrm_get_bios(struct radeon_device *rdev)
{
	return false;
}
#endif

static bool ni_read_disabled_bios(struct radeon_device *rdev)
{
	u32 bus_cntl;
	u32 d1vga_control;
	u32 d2vga_control;
	u32 vga_render_control;
	u32 rom_cntl;
	bool r;

	DRM_INFO("%s: ===> Try disabled BIOS (ni)...\n", __func__);

	bus_cntl = RREG32(R600_BUS_CNTL);
	d1vga_control = RREG32(AVIVO_D1VGA_CONTROL);
	d2vga_control = RREG32(AVIVO_D2VGA_CONTROL);
	vga_render_control = RREG32(AVIVO_VGA_RENDER_CONTROL);
	rom_cntl = RREG32(R600_ROM_CNTL);

	/* enable the rom */
	WREG32(R600_BUS_CNTL, (bus_cntl & ~R600_BIOS_ROM_DIS));
	/* Disable VGA mode */
	WREG32(AVIVO_D1VGA_CONTROL,
	       (d1vga_control & ~(AVIVO_DVGA_CONTROL_MODE_ENABLE |
		AVIVO_DVGA_CONTROL_TIMING_SELECT)));
	WREG32(AVIVO_D2VGA_CONTROL,
	       (d2vga_control & ~(AVIVO_DVGA_CONTROL_MODE_ENABLE |
		AVIVO_DVGA_CONTROL_TIMING_SELECT)));
	WREG32(AVIVO_VGA_RENDER_CONTROL,
	       (vga_render_control & ~AVIVO_VGA_VSTATUS_CNTL_MASK));
	WREG32(R600_ROM_CNTL, rom_cntl | R600_SCK_OVERWRITE);

	r = radeon_read_bios(rdev);

	/* restore regs */
	WREG32(R600_BUS_CNTL, bus_cntl);
	WREG32(AVIVO_D1VGA_CONTROL, d1vga_control);
	WREG32(AVIVO_D2VGA_CONTROL, d2vga_control);
	WREG32(AVIVO_VGA_RENDER_CONTROL, vga_render_control);
	WREG32(R600_ROM_CNTL, rom_cntl);
	return r;
}
Exemple #6
0
static int
apb_attach(device_t dev)
{
    struct apb_softc *sc;
    struct sysctl_ctx_list *sctx;
    struct sysctl_oid *soid;

    sc = device_get_softc(dev);

    /*
     * Get current bridge configuration.
     */
    sc->sc_bsc.ops_pcib_sc.domain = pci_get_domain(dev);
    sc->sc_bsc.ops_pcib_sc.secstat =
        pci_read_config(dev, PCIR_SECSTAT_1, 2);
    sc->sc_bsc.ops_pcib_sc.command =
        pci_read_config(dev, PCIR_COMMAND, 2);
    sc->sc_bsc.ops_pcib_sc.pribus =
        pci_read_config(dev, PCIR_PRIBUS_1, 1);
    sc->sc_bsc.ops_pcib_sc.bus.sec =
        pci_read_config(dev, PCIR_SECBUS_1, 1);
    sc->sc_bsc.ops_pcib_sc.bus.sub =
        pci_read_config(dev, PCIR_SUBBUS_1, 1);
    sc->sc_bsc.ops_pcib_sc.bridgectl =
        pci_read_config(dev, PCIR_BRIDGECTL_1, 2);
    sc->sc_bsc.ops_pcib_sc.seclat =
        pci_read_config(dev, PCIR_SECLAT_1, 1);
    sc->sc_iomap = pci_read_config(dev, APBR_IOMAP, 1);
    sc->sc_memmap = pci_read_config(dev, APBR_MEMMAP, 1);

    /*
     * Setup SYSCTL reporting nodes.
     */
    sctx = device_get_sysctl_ctx(dev);
    soid = device_get_sysctl_tree(dev);
    SYSCTL_ADD_UINT(sctx, SYSCTL_CHILDREN(soid), OID_AUTO, "domain",
                    CTLFLAG_RD, &sc->sc_bsc.ops_pcib_sc.domain, 0,
                    "Domain number");
    SYSCTL_ADD_UINT(sctx, SYSCTL_CHILDREN(soid), OID_AUTO, "pribus",
                    CTLFLAG_RD, &sc->sc_bsc.ops_pcib_sc.pribus, 0,
                    "Primary bus number");
    SYSCTL_ADD_UINT(sctx, SYSCTL_CHILDREN(soid), OID_AUTO, "secbus",
                    CTLFLAG_RD, &sc->sc_bsc.ops_pcib_sc.bus.sec, 0,
                    "Secondary bus number");
    SYSCTL_ADD_UINT(sctx, SYSCTL_CHILDREN(soid), OID_AUTO, "subbus",
                    CTLFLAG_RD, &sc->sc_bsc.ops_pcib_sc.bus.sub, 0,
                    "Subordinate bus number");

    ofw_pcib_gen_setup(dev);

    if (bootverbose) {
        device_printf(dev, "  domain            %d\n",
                      sc->sc_bsc.ops_pcib_sc.domain);
        device_printf(dev, "  secondary bus     %d\n",
                      sc->sc_bsc.ops_pcib_sc.bus.sec);
        device_printf(dev, "  subordinate bus   %d\n",
                      sc->sc_bsc.ops_pcib_sc.bus.sub);
        device_printf(dev, "  I/O decode        ");
        apb_map_print(sc->sc_iomap, APB_IO_SCALE);
        printf("\n");
        device_printf(dev, "  memory decode     ");
        apb_map_print(sc->sc_memmap, APB_MEM_SCALE);
        printf("\n");
    }

    device_add_child(dev, "pci", -1);
    return (bus_generic_attach(dev));
}
Exemple #7
0
static void
nvme_sim_action(struct cam_sim *sim, union ccb *ccb)
{
	struct nvme_controller *ctrlr;

	CAM_DEBUG(ccb->ccb_h.path, CAM_DEBUG_TRACE,
	    ("nvme_sim_action: func= %#x\n",
		ccb->ccb_h.func_code));

	ctrlr = sim2ctrlr(sim);

	mtx_assert(&ctrlr->lock, MA_OWNED);

	switch (ccb->ccb_h.func_code) {
	case XPT_CALC_GEOMETRY:		/* Calculate Geometry Totally nuts ? XXX */
		/* 
		 * Only meaningful for old-school SCSI disks since only the SCSI
		 * da driver generates them. Reject all these that slip through.
		 */
		/*FALLTHROUGH*/
	case XPT_ABORT:			/* Abort the specified CCB */
		ccb->ccb_h.status = CAM_REQ_INVALID;
		break;
	case XPT_SET_TRAN_SETTINGS:
		/*
		 * NVMe doesn't really have different transfer settings, but
		 * other parts of CAM think failure here is a big deal.
		 */
		ccb->ccb_h.status = CAM_REQ_CMP;
		break;
	case XPT_PATH_INQ:		/* Path routing inquiry */
	{
		struct ccb_pathinq	*cpi = &ccb->cpi;
		device_t		dev = ctrlr->dev;

		/*
		 * NVMe may have multiple LUNs on the same path. Current generation
		 * of NVMe devives support only a single name space. Multiple name
		 * space drives are coming, but it's unclear how we should report
		 * them up the stack.
		 */
		cpi->version_num = 1;
		cpi->hba_inquiry = 0;
		cpi->target_sprt = 0;
		cpi->hba_misc =  PIM_UNMAPPED | PIM_NOSCAN;
		cpi->hba_eng_cnt = 0;
		cpi->max_target = 0;
		cpi->max_lun = ctrlr->cdata.nn;
		cpi->maxio = ctrlr->max_xfer_size;
		cpi->initiator_id = 0;
		cpi->bus_id = cam_sim_bus(sim);
		cpi->base_transfer_speed = nvme_link_kBps(ctrlr);
		strlcpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN);
		strlcpy(cpi->hba_vid, "NVMe", HBA_IDLEN);
		strlcpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN);
		cpi->unit_number = cam_sim_unit(sim);
		cpi->transport = XPORT_NVME;		/* XXX XPORT_PCIE ? */
		cpi->transport_version = nvme_mmio_read_4(ctrlr, vs);
		cpi->protocol = PROTO_NVME;
		cpi->protocol_version = nvme_mmio_read_4(ctrlr, vs);
		cpi->xport_specific.nvme.nsid = xpt_path_lun_id(ccb->ccb_h.path);
		cpi->xport_specific.nvme.domain = pci_get_domain(dev);
		cpi->xport_specific.nvme.bus = pci_get_bus(dev);
		cpi->xport_specific.nvme.slot = pci_get_slot(dev);
		cpi->xport_specific.nvme.function = pci_get_function(dev);
		cpi->xport_specific.nvme.extra = 0;
		cpi->ccb_h.status = CAM_REQ_CMP;
		break;
	}
	case XPT_GET_TRAN_SETTINGS:	/* Get transport settings */
	{
		struct ccb_trans_settings	*cts;
		struct ccb_trans_settings_nvme	*nvmep;
		struct ccb_trans_settings_nvme	*nvmex;
		device_t dev;
		uint32_t status, caps;

		dev = ctrlr->dev;
		cts = &ccb->cts;
		nvmex = &cts->xport_specific.nvme;
		nvmep = &cts->proto_specific.nvme;

		status = pcie_read_config(dev, PCIER_LINK_STA, 2);
		caps = pcie_read_config(dev, PCIER_LINK_CAP, 2);
		nvmex->valid = CTS_NVME_VALID_SPEC | CTS_NVME_VALID_LINK;
		nvmex->spec = nvme_mmio_read_4(ctrlr, vs);
		nvmex->speed = status & PCIEM_LINK_STA_SPEED;
		nvmex->lanes = (status & PCIEM_LINK_STA_WIDTH) >> 4;
		nvmex->max_speed = caps & PCIEM_LINK_CAP_MAX_SPEED;
		nvmex->max_lanes = (caps & PCIEM_LINK_CAP_MAX_WIDTH) >> 4;

		/* XXX these should be something else maybe ? */
		nvmep->valid = 1;
		nvmep->spec = nvmex->spec;

		cts->transport = XPORT_NVME;
		cts->protocol = PROTO_NVME;
		cts->ccb_h.status = CAM_REQ_CMP;
		break;
	}
	case XPT_TERM_IO:		/* Terminate the I/O process */
		/*
		 * every driver handles this, but nothing generates it. Assume
		 * it's OK to just say 'that worked'.
		 */
		/*FALLTHROUGH*/
	case XPT_RESET_DEV:		/* Bus Device Reset the specified device */
	case XPT_RESET_BUS:		/* Reset the specified bus */
		/*
		 * NVMe doesn't really support physically resetting the bus. It's part
		 * of the bus scanning dance, so return sucess to tell the process to
		 * proceed.
		 */
		ccb->ccb_h.status = CAM_REQ_CMP;
		break;
	case XPT_NVME_IO:		/* Execute the requested I/O operation */
	case XPT_NVME_ADMIN:		/* or Admin operation */
		nvme_sim_nvmeio(sim, ccb);
		return;			/* no done */
	default:
		ccb->ccb_h.status = CAM_REQ_INVALID;
		break;
	}
	xpt_done(ccb);
}
Exemple #8
0
static int
cbb_pci_attach(device_t brdev)
{
	static int curr_bus_number = 2; /* XXX EVILE BAD (see below) */
	struct cbb_softc *sc = (struct cbb_softc *)device_get_softc(brdev);
	struct sysctl_ctx_list *sctx;
	struct sysctl_oid *soid;
	int rid;
	device_t parent;
	uint32_t pribus;

	parent = device_get_parent(brdev);
	mtx_init(&sc->mtx, device_get_nameunit(brdev), "cbb", MTX_DEF);
	sc->chipset = cbb_chipset(pci_get_devid(brdev), NULL);
	sc->dev = brdev;
	sc->cbdev = NULL;
	sc->exca[0].pccarddev = NULL;
	sc->domain = pci_get_domain(brdev);
	sc->secbus = pci_read_config(brdev, PCIR_SECBUS_2, 1);
	sc->subbus = pci_read_config(brdev, PCIR_SUBBUS_2, 1);
	sc->pribus = pcib_get_bus(parent);
	SLIST_INIT(&sc->rl);
	cbb_powerstate_d0(brdev);

	rid = CBBR_SOCKBASE;
	sc->base_res = bus_alloc_resource_any(brdev, SYS_RES_MEMORY, &rid,
	    RF_ACTIVE);
	if (!sc->base_res) {
		device_printf(brdev, "Could not map register memory\n");
		mtx_destroy(&sc->mtx);
		return (ENOMEM);
	} else {
		DEVPRINTF((brdev, "Found memory at %08lx\n",
		    rman_get_start(sc->base_res)));
	}

	sc->bst = rman_get_bustag(sc->base_res);
	sc->bsh = rman_get_bushandle(sc->base_res);
	exca_init(&sc->exca[0], brdev, sc->bst, sc->bsh, CBB_EXCA_OFFSET);
	sc->exca[0].flags |= EXCA_HAS_MEMREG_WIN;
	sc->exca[0].chipset = EXCA_CARDBUS;
	sc->chipinit = cbb_chipinit;
	sc->chipinit(sc);

	/*Sysctls*/
	sctx = device_get_sysctl_ctx(brdev);
	soid = device_get_sysctl_tree(brdev);
	SYSCTL_ADD_UINT(sctx, SYSCTL_CHILDREN(soid), OID_AUTO, "domain",
	    CTLFLAG_RD, &sc->domain, 0, "Domain number");
	SYSCTL_ADD_UINT(sctx, SYSCTL_CHILDREN(soid), OID_AUTO, "pribus",
	    CTLFLAG_RD, &sc->pribus, 0, "Primary bus number");
	SYSCTL_ADD_UINT(sctx, SYSCTL_CHILDREN(soid), OID_AUTO, "secbus",
	    CTLFLAG_RD, &sc->secbus, 0, "Secondary bus number");
	SYSCTL_ADD_UINT(sctx, SYSCTL_CHILDREN(soid), OID_AUTO, "subbus",
	    CTLFLAG_RD, &sc->subbus, 0, "Subordinate bus number");
#if 0
	SYSCTL_ADD_UINT(sctx, SYSCTL_CHILDREN(soid), OID_AUTO, "memory",
	    CTLFLAG_RD, &sc->subbus, 0, "Memory window open");
	SYSCTL_ADD_UINT(sctx, SYSCTL_CHILDREN(soid), OID_AUTO, "premem",
	    CTLFLAG_RD, &sc->subbus, 0, "Prefetch memroy window open");
	SYSCTL_ADD_UINT(sctx, SYSCTL_CHILDREN(soid), OID_AUTO, "io1",
	    CTLFLAG_RD, &sc->subbus, 0, "io range 1 open");
	SYSCTL_ADD_UINT(sctx, SYSCTL_CHILDREN(soid), OID_AUTO, "io2",
	    CTLFLAG_RD, &sc->subbus, 0, "io range 2 open");
#endif

	/*
	 * This is a gross hack.  We should be scanning the entire pci
	 * tree, assigning bus numbers in a way such that we (1) can
	 * reserve 1 extra bus just in case and (2) all sub busses
	 * are in an appropriate range.
	 */
	DEVPRINTF((brdev, "Secondary bus is %d\n", sc->secbus));
	pribus = pci_read_config(brdev, PCIR_PRIBUS_2, 1);
	if (sc->secbus == 0 || sc->pribus != pribus) {
		if (curr_bus_number <= sc->pribus)
			curr_bus_number = sc->pribus + 1;
		if (pribus != sc->pribus) {
			DEVPRINTF((brdev, "Setting primary bus to %d\n",
			    sc->pribus));
			pci_write_config(brdev, PCIR_PRIBUS_2, sc->pribus, 1);
		}
		sc->secbus = curr_bus_number++;
		sc->subbus = curr_bus_number++;
		DEVPRINTF((brdev, "Secondary bus set to %d subbus %d\n",
		    sc->secbus, sc->subbus));
		pci_write_config(brdev, PCIR_SECBUS_2, sc->secbus, 1);
		pci_write_config(brdev, PCIR_SUBBUS_2, sc->subbus, 1);
	}

	/* attach children */
	sc->cbdev = device_add_child(brdev, "cardbus", -1);
	if (sc->cbdev == NULL)
		DEVPRINTF((brdev, "WARNING: cannot add cardbus bus.\n"));
	else if (device_probe_and_attach(sc->cbdev) != 0)
		DEVPRINTF((brdev, "WARNING: cannot attach cardbus bus!\n"));

	sc->exca[0].pccarddev = device_add_child(brdev, "pccard", -1);
	if (sc->exca[0].pccarddev == NULL)
		DEVPRINTF((brdev, "WARNING: cannot add pccard bus.\n"));
	else if (device_probe_and_attach(sc->exca[0].pccarddev) != 0)
		DEVPRINTF((brdev, "WARNING: cannot attach pccard bus.\n"));

	/* Map and establish the interrupt. */
	rid = 0;
	sc->irq_res = bus_alloc_resource_any(brdev, SYS_RES_IRQ, &rid,
	    RF_SHAREABLE | RF_ACTIVE);
	if (sc->irq_res == NULL) {
		device_printf(brdev, "Unable to map IRQ...\n");
		goto err;
	}

	if (bus_setup_intr(brdev, sc->irq_res, INTR_TYPE_AV | INTR_MPSAFE,
	    cbb_pci_filt, NULL, sc, &sc->intrhand)) {
		device_printf(brdev, "couldn't establish interrupt\n");
		goto err;
	}

	/* reset 16-bit pcmcia bus */
	exca_clrb(&sc->exca[0], EXCA_INTR, EXCA_INTR_RESET);

	/* turn off power */
	cbb_power(brdev, CARD_OFF);

	/* CSC Interrupt: Card detect interrupt on */
	cbb_setb(sc, CBB_SOCKET_MASK, CBB_SOCKET_MASK_CD);

	/* reset interrupt */
	cbb_set(sc, CBB_SOCKET_EVENT, cbb_get(sc, CBB_SOCKET_EVENT));

	if (bootverbose)
		cbb_print_config(brdev);

	/* Start the thread */
	if (kproc_create(cbb_event_thread, sc, &sc->event_thread, 0, 0,
	    "%s event thread", device_get_nameunit(brdev))) {
		device_printf(brdev, "unable to create event thread.\n");
		panic("cbb_create_event_thread");
	}
	sc->sc_root_token = root_mount_hold(device_get_nameunit(sc->dev));
	return (0);
err:
	if (sc->irq_res)
		bus_release_resource(brdev, SYS_RES_IRQ, 0, sc->irq_res);
	if (sc->base_res) {
		bus_release_resource(brdev, SYS_RES_MEMORY, CBBR_SOCKBASE,
		    sc->base_res);
	}
	mtx_destroy(&sc->mtx);
	return (ENOMEM);
}