Beispiel #1
0
static int
rtw_pci_attach(device_t dev)
{
	struct rtw_softc *sc = device_get_softc(dev);
	struct rtw_regs *regs = &sc->sc_regs;
	int i, error;

	/*
	 * No power management hooks.
	 * XXX Maybe we should add some!
	 */
	sc->sc_flags |= RTW_F_ENABLED;

	sc->sc_rev = pci_get_revid(dev);

#ifndef BURN_BRIDGES
	if (pci_get_powerstate(dev) != PCI_POWERSTATE_D0) {
		uint32_t mem, port, irq;
						
		mem = pci_read_config(dev, RTW_PCI_MMBA, 4);
		port = pci_read_config(dev, RTW_PCI_IOBA, 4);
		irq = pci_read_config(dev, PCIR_INTLINE, 4);
		
		device_printf(dev, "chip is in D%d power mode "
		    "-- setting to D0\n", pci_get_powerstate(dev));

		pci_set_powerstate(dev, PCI_POWERSTATE_D0);

		pci_write_config(dev, RTW_PCI_MMBA, mem, 4);
		pci_write_config(dev, RTW_PCI_IOBA, port, 4);
		pci_write_config(dev, PCIR_INTLINE, irq, 4);
	}
#endif	/* !BURN_BRIDGES */

	/* Enable PCI bus master */
	pci_enable_busmaster(dev);

	/* Allocate IO memory/port */
	for (i = 0; i < NELEM(rtw_pci_regs); ++i) {
		regs->r_rid = rtw_pci_regs[i].reg_rid;
		regs->r_type = rtw_pci_regs[i].reg_type;
		regs->r_res = bus_alloc_resource_any(dev, regs->r_type,
						     &regs->r_rid, RF_ACTIVE);
		if (regs->r_res != NULL)
			break;
	}
	if (regs->r_res == NULL) {
		device_printf(dev, "can't allocate IO mem/port\n");
		return ENXIO;
	}
	regs->r_bh = rman_get_bushandle(regs->r_res);
	regs->r_bt = rman_get_bustag(regs->r_res);

	error = rtw_attach(dev);
	if (error)
		rtw_pci_detach(dev);
	return error;
}
Beispiel #2
0
static int
ral_pci_attach(device_t dev)
{
	struct ral_pci_softc *psc = device_get_softc(dev);
	struct rt2560_softc *sc = &psc->u.sc_rt2560;
	int error;

	if (pci_get_powerstate(dev) != PCI_POWERSTATE_D0) {
		device_printf(dev, "chip is in D%d power mode "
		    "-- setting to D0\n", pci_get_powerstate(dev));
		pci_set_powerstate(dev, PCI_POWERSTATE_D0);
	}

	/* enable bus-mastering */
	pci_enable_busmaster(dev);

	psc->sc_opns = (pci_get_device(dev) == 0x0201) ? &ral_rt2560_opns :
	    &ral_rt2661_opns;

	psc->mem_rid = RAL_PCI_BAR0;
	psc->mem = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &psc->mem_rid,
	    RF_ACTIVE);
	if (psc->mem == NULL) {
		device_printf(dev, "could not allocate memory resource\n");
		return ENXIO;
	}

	sc->sc_st = rman_get_bustag(psc->mem);
	sc->sc_sh = rman_get_bushandle(psc->mem);
	sc->sc_invalid = 1;
	
	psc->irq_rid = 0;
	psc->irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &psc->irq_rid,
	    RF_ACTIVE | RF_SHAREABLE);
	if (psc->irq == NULL) {
		device_printf(dev, "could not allocate interrupt resource\n");
		return ENXIO;
	}

	error = (*psc->sc_opns->attach)(dev, pci_get_device(dev));
	if (error != 0)
		return error;

	/*
	 * Hook our interrupt after all initialization is complete.
	 */
	error = bus_setup_intr(dev, psc->irq, INTR_TYPE_NET | INTR_MPSAFE,
	    NULL, psc->sc_opns->intr, psc, &psc->sc_ih);
	if (error != 0) {
		device_printf(dev, "could not set up interrupt\n");
		return error;
	}
	sc->sc_invalid = 0;
	
	return 0;
}
Beispiel #3
0
static int
vga_pci_get_powerstate(device_t dev, device_t child)
{

	device_printf(dev, "child %s requested pci_get_powerstate\n",
	    device_get_nameunit(child));
	return (pci_get_powerstate(dev));
}
Beispiel #4
0
static int
ohci_pci_take_controller(device_t self)
{
	uint32_t reg;
	uint32_t int_line;

	if (pci_get_powerstate(self) != PCI_POWERSTATE_D0) {
		device_printf(self, "chip is in D%d mode "
		    "-- setting to D0\n", pci_get_powerstate(self));
		reg = pci_read_config(self, PCI_CBMEM, 4);
		int_line = pci_read_config(self, PCIR_INTLINE, 4);
		pci_set_powerstate(self, PCI_POWERSTATE_D0);
		pci_write_config(self, PCI_CBMEM, reg, 4);
		pci_write_config(self, PCIR_INTLINE, int_line, 4);
	}
	return (0);
}
Beispiel #5
0
pcireg_t
pci_min_powerstate(pci_chipset_tag_t pc, pcitag_t tag)
{
#if NACPI > 0
	return acpi_pci_min_powerstate(pc, tag);
#else
	return pci_get_powerstate(pc, tag);
#endif
}
static int
ohci_pci_resume(device_t self)
{
	ohci_softc_t *sc = device_get_softc(self);
	uint32_t reg, int_line;

	if (pci_get_powerstate(self) != PCI_POWERSTATE_D0) {
		device_printf(self, "chip is in D%d mode "
		    "-- setting to D0\n", pci_get_powerstate(self));
		reg = pci_read_config(self, PCI_CBMEM, 4);
		int_line = pci_read_config(self, PCIR_INTLINE, 4);
		pci_set_powerstate(self, PCI_POWERSTATE_D0);
		pci_write_config(self, PCI_CBMEM, reg, 4);
		pci_write_config(self, PCIR_INTLINE, int_line, 4);
	}
	ohci_resume(sc);

	bus_generic_resume(self);
	return (0);
}
Beispiel #7
0
/*
 * Still need this because the pci code only does power for type 0
 * header devices.
 */
static void
cbb_powerstate_d0(device_t dev)
{
	u_int32_t membase, irq;

	if (pci_get_powerstate(dev) != PCI_POWERSTATE_D0) {
		/* Save important PCI config data. */
		membase = pci_read_config(dev, CBBR_SOCKBASE, 4);
		irq = pci_read_config(dev, PCIR_INTLINE, 4);

		/* Reset the power state. */
		device_printf(dev, "chip is in D%d power mode "
		    "-- setting to D0\n", pci_get_powerstate(dev));

		pci_set_powerstate(dev, PCI_POWERSTATE_D0);

		/* Restore PCI config data. */
		pci_write_config(dev, CBBR_SOCKBASE, membase, 4);
		pci_write_config(dev, PCIR_INTLINE, irq, 4);
	}
}
Beispiel #8
0
static int
ohci_pci_resume(device_t self)
{
	ohci_softc_t *sc = device_get_softc(self);

#ifndef BURN_BRIDGES
	uint32_t reg, int_line;

	if (pci_get_powerstate(self) != PCI_POWERSTATE_D0) {
		device_printf(self, "chip is in D%d mode "
		        "-- setting to D0\n", pci_get_powerstate(self));
		reg = pci_read_config(self, PCI_CBMEM, 4);
		int_line = pci_read_config(self, PCIR_INTLINE, 4);
		pci_set_powerstate(self, PCI_POWERSTATE_D0);
		pci_write_config(self, PCI_CBMEM, reg, 4);
		pci_write_config(self, PCIR_INTLINE, int_line, 4);
	}
#endif	/* !BURN_BRIDGES */

	ohci_power(PWR_RESUME, sc);
	bus_generic_resume(self);

	return 0;
}
Beispiel #9
0
/*
 * PCI power manangement
 */
static int
acpi_pci_set_powerstate_method(device_t dev, device_t child, int state)
{
	ACPI_HANDLE h;
	ACPI_STATUS status;
	int old_state, error;

	error = 0;
	if (state < ACPI_STATE_D0 || state > ACPI_STATE_D3)
		return (EINVAL);

	/*
	 * We set the state using PCI Power Management outside of setting
	 * the ACPI state.  This means that when powering down a device, we
	 * first shut it down using PCI, and then using ACPI, which lets ACPI
	 * try to power down any Power Resources that are now no longer used.
	 * When powering up a device, we let ACPI set the state first so that
	 * it can enable any needed Power Resources before changing the PCI
	 * power state.
	 */
	ACPI_SERIAL_BEGIN(pci_powerstate);
	old_state = pci_get_powerstate(child);
	if (old_state < state && pci_do_power_suspend) {
		error = pci_set_powerstate_method(dev, child, state);
		if (error)
			goto out;
	}
	h = acpi_get_handle(child);
	status = acpi_pwr_switch_consumer(h, state);
	if (ACPI_SUCCESS(status)) {
		if (bootverbose)
			device_printf(dev, "set ACPI power state D%d on %s\n",
			    state, acpi_name(h));
	} else if (status != AE_NOT_FOUND)
		device_printf(dev,
		    "failed to set ACPI power state D%d on %s: %s\n",
		    state, acpi_name(h), AcpiFormatException(status));
	if (old_state > state && pci_do_power_resume)
		error = pci_set_powerstate_method(dev, child, state);

out:
	ACPI_SERIAL_END(pci_powerstate);
	return (error);
}
Beispiel #10
0
int
pci_activate(pci_chipset_tag_t pc, pcitag_t tag, device_t dev,
    int (*wakefun)(pci_chipset_tag_t, pcitag_t, device_t, pcireg_t))
{
	pcireg_t pmode;
	int error;

	if ((error = pci_get_powerstate(pc, tag, &pmode)))
		return error;

	switch (pmode) {
	case PCI_PMCSR_STATE_D0:
		break;
	case PCI_PMCSR_STATE_D3:
		if (wakefun == NULL) {
			/*
			 * The card has lost all configuration data in
			 * this state, so punt.
			 */
			aprint_error_dev(dev,
			    "unable to wake up from power state D3\n");
			return EOPNOTSUPP;
		}
		/*FALLTHROUGH*/
	default:
		if (wakefun) {
			error = (*wakefun)(pc, tag, dev, pmode);
			if (error)
				return error;
		}
		aprint_normal_dev(dev, "waking up from power state D%d\n",
		    pmode);
		if ((error = pci_set_powerstate(pc, tag, PCI_PMCSR_STATE_D0)))
			return error;
	}
	return 0;
}
Beispiel #11
0
static int
cs4281_pci_attach(device_t dev)
{
    struct sc_info *sc;
    struct ac97_info *codec = NULL;
    char status[SND_STATUSLEN];

    sc = malloc(sizeof(*sc), M_DEVBUF, M_WAITOK | M_ZERO);
    sc->dev = dev;
    sc->type = pci_get_devid(dev);

    pci_enable_busmaster(dev);

#if __FreeBSD_version > 500000
    if (pci_get_powerstate(dev) != PCI_POWERSTATE_D0) {
	/* Reset the power state. */
	device_printf(dev, "chip is in D%d power mode "
		      "-- setting to D0\n", pci_get_powerstate(dev));

	pci_set_powerstate(dev, PCI_POWERSTATE_D0);
    }
#else
    data = pci_read_config(dev, CS4281PCI_PMCS_OFFSET, 4);
    if (data & CS4281PCI_PMCS_PS_MASK) {
	    /* Reset the power state. */
	    device_printf(dev, "chip is in D%d power mode "
			  "-- setting to D0\n",
			  data & CS4281PCI_PMCS_PS_MASK);
	    pci_write_config(dev, CS4281PCI_PMCS_OFFSET,
			     data & ~CS4281PCI_PMCS_PS_MASK, 4);
    }
#endif

    sc->regid   = PCIR_BAR(0);
    sc->regtype = SYS_RES_MEMORY;
    sc->reg = bus_alloc_resource(dev, sc->regtype, &sc->regid,
				 0, ~0, CS4281PCI_BA0_SIZE, RF_ACTIVE);
    if (!sc->reg) {
	sc->regtype = SYS_RES_IOPORT;
	sc->reg = bus_alloc_resource(dev, sc->regtype, &sc->regid,
				     0, ~0, CS4281PCI_BA0_SIZE, RF_ACTIVE);
	if (!sc->reg) {
	    device_printf(dev, "unable to allocate register space\n");
	    goto bad;
	}
    }
    sc->st = rman_get_bustag(sc->reg);
    sc->sh = rman_get_bushandle(sc->reg);

    sc->memid = PCIR_BAR(1);
    sc->mem = bus_alloc_resource(dev, SYS_RES_MEMORY, &sc->memid, 0,
				 ~0, CS4281PCI_BA1_SIZE, RF_ACTIVE);
    if (sc->mem == NULL) {
	device_printf(dev, "unable to allocate fifo space\n");
	goto bad;
    }

    sc->irqid = 0;
    sc->irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &sc->irqid,
				     RF_ACTIVE | RF_SHAREABLE);
    if (!sc->irq) {
	device_printf(dev, "unable to allocate interrupt\n");
	goto bad;
    }

    if (snd_setup_intr(dev, sc->irq, 0, cs4281_intr, sc, &sc->ih)) {
	device_printf(dev, "unable to setup interrupt\n");
	goto bad;
    }

    sc->bufsz = pcm_getbuffersize(dev, 4096, CS4281_DEFAULT_BUFSZ, 65536);

    if (bus_dma_tag_create(/*parent*/bus_get_dma_tag(dev), /*alignment*/2,
			   /*boundary*/0,
			   /*lowaddr*/BUS_SPACE_MAXADDR_32BIT,
			   /*highaddr*/BUS_SPACE_MAXADDR,
			   /*filter*/NULL, /*filterarg*/NULL,
			   /*maxsize*/sc->bufsz, /*nsegments*/1,
			   /*maxsegz*/0x3ffff,
			   /*flags*/0, /*lockfunc*/busdma_lock_mutex,
			   /*lockarg*/&Giant, &sc->parent_dmat) != 0) {
	device_printf(dev, "unable to create dma tag\n");
	goto bad;
    }

    /* power up */
    cs4281_power(sc, 0);

    /* init chip */
    if (cs4281_init(sc) == -1) {
	device_printf(dev, "unable to initialize the card\n");
	goto bad;
    }

    /* create/init mixer */
    codec = AC97_CREATE(dev, sc, cs4281_ac97);
    if (codec == NULL)
        goto bad;

    mixer_init(dev, ac97_getmixerclass(), codec);

    if (pcm_register(dev, sc, 1, 1))
	goto bad;

    pcm_addchan(dev, PCMDIR_PLAY, &cs4281chan_class, sc);
    pcm_addchan(dev, PCMDIR_REC, &cs4281chan_class, sc);

    snprintf(status, SND_STATUSLEN, "at %s 0x%lx irq %ld %s",
	     (sc->regtype == SYS_RES_IOPORT)? "io" : "memory",
	     rman_get_start(sc->reg), rman_get_start(sc->irq),PCM_KLDSTRING(snd_cs4281));
    pcm_setstatus(dev, status);

    return 0;

 bad:
    if (codec)
	ac97_destroy(codec);
    if (sc->reg)
	bus_release_resource(dev, sc->regtype, sc->regid, sc->reg);
    if (sc->mem)
	bus_release_resource(dev, SYS_RES_MEMORY, sc->memid, sc->mem);
    if (sc->ih)
	bus_teardown_intr(dev, sc->irq, sc->ih);
    if (sc->irq)
	bus_release_resource(dev, SYS_RES_IRQ, sc->irqid, sc->irq);
    if (sc->parent_dmat)
	bus_dma_tag_destroy(sc->parent_dmat);
    free(sc, M_DEVBUF);

    return ENXIO;
}
Beispiel #12
0
int
pci_probe_device(struct pci_softc *sc, pcitag_t tag,
    int (*match)(const struct pci_attach_args *),
    struct pci_attach_args *pap)
{
	pci_chipset_tag_t pc = sc->sc_pc;
	struct pci_attach_args pa;
	pcireg_t id, /* csr, */ pciclass, intr, bhlcr, bar, endbar;
#ifdef __HAVE_PCI_MSI_MSIX
	pcireg_t cap;
	int off;
#endif
	int ret, pin, bus, device, function, i, width;
	int locs[PCICF_NLOCS];

	pci_decompose_tag(pc, tag, &bus, &device, &function);

	/* a driver already attached? */
	if (sc->PCI_SC_DEVICESC(device, function).c_dev != NULL && !match)
		return 0;

	bhlcr = pci_conf_read(pc, tag, PCI_BHLC_REG);
	if (PCI_HDRTYPE_TYPE(bhlcr) > 2)
		return 0;

	id = pci_conf_read(pc, tag, PCI_ID_REG);
	/* csr = pci_conf_read(pc, tag, PCI_COMMAND_STATUS_REG); */
	pciclass = pci_conf_read(pc, tag, PCI_CLASS_REG);

	/* Invalid vendor ID value? */
	if (PCI_VENDOR(id) == PCI_VENDOR_INVALID)
		return 0;
	/* XXX Not invalid, but we've done this ~forever. */
	if (PCI_VENDOR(id) == 0)
		return 0;

	/* Collect memory range info */
	memset(sc->PCI_SC_DEVICESC(device, function).c_range, 0,
	    sizeof(sc->PCI_SC_DEVICESC(device, function).c_range));
	i = 0;
	switch (PCI_HDRTYPE_TYPE(bhlcr)) {
	case PCI_HDRTYPE_PPB:
		endbar = PCI_MAPREG_PPB_END;
		break;
	case PCI_HDRTYPE_PCB:
		endbar = PCI_MAPREG_PCB_END;
		break;
	default:
		endbar = PCI_MAPREG_END;
		break;
	}
	for (bar = PCI_MAPREG_START; bar < endbar; bar += width) {
		struct pci_range *r;
		pcireg_t type;

		width = 4;
		if (pci_mapreg_probe(pc, tag, bar, &type) == 0)
			continue;

		if (PCI_MAPREG_TYPE(type) == PCI_MAPREG_TYPE_MEM) {
			if (PCI_MAPREG_MEM_TYPE(type) ==
			    PCI_MAPREG_MEM_TYPE_64BIT)
				width = 8;

			r = &sc->PCI_SC_DEVICESC(device, function).c_range[i++];
			if (pci_mapreg_info(pc, tag, bar, type,
			    &r->r_offset, &r->r_size, &r->r_flags) != 0)
				break;
			if ((PCI_VENDOR(id) == PCI_VENDOR_ATI) && (bar == 0x10)
			    && (r->r_size == 0x1000000)) {
				struct pci_range *nr;
				/*
				 * this has to be a mach64
				 * split things up so each half-aperture can
				 * be mapped PREFETCHABLE except the last page
				 * which may contain registers
				 */
				r->r_size = 0x7ff000;
				r->r_flags = BUS_SPACE_MAP_LINEAR |
					     BUS_SPACE_MAP_PREFETCHABLE;
				nr = &sc->PCI_SC_DEVICESC(device,
				    function).c_range[i++];
				nr->r_offset = r->r_offset + 0x800000;
				nr->r_size = 0x7ff000;
				nr->r_flags = BUS_SPACE_MAP_LINEAR |
					      BUS_SPACE_MAP_PREFETCHABLE;
			}
			
		}
	}

	pa.pa_iot = sc->sc_iot;
	pa.pa_memt = sc->sc_memt;
	pa.pa_dmat = sc->sc_dmat;
	pa.pa_dmat64 = sc->sc_dmat64;
	pa.pa_pc = pc;
	pa.pa_bus = bus;
	pa.pa_device = device;
	pa.pa_function = function;
	pa.pa_tag = tag;
	pa.pa_id = id;
	pa.pa_class = pciclass;

	/*
	 * Set up memory, I/O enable, and PCI command flags
	 * as appropriate.
	 */
	pa.pa_flags = sc->sc_flags;

	/*
	 * If the cache line size is not configured, then
	 * clear the MRL/MRM/MWI command-ok flags.
	 */
	if (PCI_CACHELINE(bhlcr) == 0) {
		pa.pa_flags &= ~(PCI_FLAGS_MRL_OKAY|
		    PCI_FLAGS_MRM_OKAY|PCI_FLAGS_MWI_OKAY);
	}

	if (sc->sc_bridgetag == NULL) {
		pa.pa_intrswiz = 0;
		pa.pa_intrtag = tag;
	} else {
		pa.pa_intrswiz = sc->sc_intrswiz + device;
		pa.pa_intrtag = sc->sc_intrtag;
	}

	intr = pci_conf_read(pc, tag, PCI_INTERRUPT_REG);

	pin = PCI_INTERRUPT_PIN(intr);
	pa.pa_rawintrpin = pin;
	if (pin == PCI_INTERRUPT_PIN_NONE) {
		/* no interrupt */
		pa.pa_intrpin = 0;
	} else {
		/*
		 * swizzle it based on the number of busses we're
		 * behind and our device number.
		 */
		pa.pa_intrpin = 	/* XXX */
		    ((pin + pa.pa_intrswiz - 1) % 4) + 1;
	}
	pa.pa_intrline = PCI_INTERRUPT_LINE(intr);

#ifdef __HAVE_PCI_MSI_MSIX
	if (pci_get_ht_capability(pc, tag, PCI_HT_CAP_MSIMAP, &off, &cap)) {
		/*
		 * XXX Should we enable MSI mapping ourselves on
		 * systems that have it disabled?
		 */
		if (cap & PCI_HT_MSI_ENABLED) {
			uint64_t addr;
			if ((cap & PCI_HT_MSI_FIXED) == 0) {
				addr = pci_conf_read(pc, tag,
				    off + PCI_HT_MSI_ADDR_LO);
				addr |= (uint64_t)pci_conf_read(pc, tag,
				    off + PCI_HT_MSI_ADDR_HI) << 32;
			} else
				addr = PCI_HT_MSI_FIXED_ADDR;

			/*
			 * XXX This will fail to enable MSI on systems
			 * that don't use the canonical address.
			 */
			if (addr == PCI_HT_MSI_FIXED_ADDR) {
				pa.pa_flags |= PCI_FLAGS_MSI_OKAY;
				pa.pa_flags |= PCI_FLAGS_MSIX_OKAY;
			}
		}
	}
#endif

	if (match != NULL) {
		ret = (*match)(&pa);
		if (ret != 0 && pap != NULL)
			*pap = pa;
	} else {
		struct pci_child *c;
		locs[PCICF_DEV] = device;
		locs[PCICF_FUNCTION] = function;

		c = &sc->PCI_SC_DEVICESC(device, function);
		pci_conf_capture(pc, tag, &c->c_conf);
		if (pci_get_powerstate(pc, tag, &c->c_powerstate) == 0)
			c->c_psok = true;
		else
			c->c_psok = false;

		c->c_dev = config_found_sm_loc(sc->sc_dev, "pci", locs, &pa,
					     pciprint, config_stdsubmatch);

		ret = (c->c_dev != NULL);
	}

	return ret;
}
Beispiel #13
0
int
ppbactivate(struct device *self, int act)
{
	struct ppb_softc *sc = (void *)self;
	pci_chipset_tag_t pc = sc->sc_pc;
	pcitag_t tag = sc->sc_tag;
	pcireg_t blr, reg;
	int off, rv = 0;

	switch (act) {
	case DVACT_QUIESCE:
		rv = config_activate_children(self, act);
		break;
	case DVACT_SUSPEND:
		rv = config_activate_children(self, act);

		/* Save registers that may get lost. */
		sc->sc_csr = pci_conf_read(pc, tag, PCI_COMMAND_STATUS_REG);
		sc->sc_bhlcr = pci_conf_read(pc, tag, PCI_BHLC_REG);
		sc->sc_bir = pci_conf_read(pc, tag, PPB_REG_BUSINFO);
		sc->sc_bcr = pci_conf_read(pc, tag, PPB_REG_BRIDGECONTROL);
		sc->sc_int = pci_conf_read(pc, tag, PCI_INTERRUPT_REG);
		if (sc->sc_cap_off)
			sc->sc_slcsr = pci_conf_read(pc, tag,
			    sc->sc_cap_off + PCI_PCIE_SLCSR);

		if (pci_get_capability(pc, tag, PCI_CAP_MSI, &off, &reg)) {
			sc->sc_msi_ma = pci_conf_read(pc, tag,
			    off + PCI_MSI_MA);
			if (reg & PCI_MSI_MC_C64) {
				sc->sc_msi_mau32 = pci_conf_read(pc, tag,
				    off + PCI_MSI_MAU32);
				sc->sc_msi_md = pci_conf_read(pc, tag,
				    off + PCI_MSI_MD64);
			} else {
				sc->sc_msi_md = pci_conf_read(pc, tag,
				    off + PCI_MSI_MD32);
			}
			sc->sc_msi_mc = reg;
		}

		if (pci_dopm) {	
			/* Place the bridge into D3. */
			sc->sc_pmcsr_state = pci_get_powerstate(pc, tag);
			pci_set_powerstate(pc, tag, PCI_PMCSR_STATE_D3);
		}
		break;
	case DVACT_RESUME:
		if (pci_dopm) {
			/* Restore power. */
			pci_set_powerstate(pc, tag, sc->sc_pmcsr_state);
		}

		/* Restore the registers saved above. */
		pci_conf_write(pc, tag, PCI_BHLC_REG, sc->sc_bhlcr);
		pci_conf_write(pc, tag, PPB_REG_BUSINFO, sc->sc_bir);
		pci_conf_write(pc, tag, PPB_REG_BRIDGECONTROL, sc->sc_bcr);
		pci_conf_write(pc, tag, PCI_INTERRUPT_REG, sc->sc_int);
		if (sc->sc_cap_off)
			pci_conf_write(pc, tag,
			    sc->sc_cap_off + PCI_PCIE_SLCSR, sc->sc_slcsr);

		/* Restore I/O window. */
		blr = pci_conf_read(pc, tag, PPB_REG_IOSTATUS);
		blr &= 0xffff0000;
		blr |= sc->sc_iolimit & PPB_IO_MASK;
		blr |= (sc->sc_iobase >> PPB_IO_SHIFT);
		pci_conf_write(pc, tag, PPB_REG_IOSTATUS, blr);
		blr = (sc->sc_iobase & 0xffff0000) >> 16;
		blr |= sc->sc_iolimit & 0xffff0000;
		pci_conf_write(pc, tag, PPB_REG_IO_HI, blr);

		/* Restore memory mapped I/O window. */
		blr = sc->sc_memlimit & PPB_MEM_MASK;
		blr |= (sc->sc_membase >> PPB_MEM_SHIFT);
		pci_conf_write(pc, tag, PPB_REG_MEM, blr);

		/* Restore prefetchable MMI/O window. */
		blr = sc->sc_pmemlimit & PPB_MEM_MASK;
		blr |= (sc->sc_pmembase >> PPB_MEM_SHIFT);
		pci_conf_write(pc, tag, PPB_REG_PREFMEM, blr);
#ifdef __LP64__
		pci_conf_write(pc, tag, PPB_REG_PREFBASE_HI32,
		    sc->sc_pmembase >> 32);
		pci_conf_write(pc, tag, PPB_REG_PREFLIM_HI32,
		    sc->sc_pmemlimit >> 32);
#endif

		if (pci_get_capability(pc, tag, PCI_CAP_MSI, &off, &reg)) {
			pci_conf_write(pc, tag, off + PCI_MSI_MA,
			    sc->sc_msi_ma);
			if (reg & PCI_MSI_MC_C64) {
				pci_conf_write(pc, tag, off + PCI_MSI_MAU32,
				    sc->sc_msi_mau32);
				pci_conf_write(pc, tag, off + PCI_MSI_MD64,
				    sc->sc_msi_md);
			} else {
				pci_conf_write(pc, tag, off + PCI_MSI_MD32,
				    sc->sc_msi_md);
			}
			pci_conf_write(pc, tag, off + PCI_MSI_MC,
			    sc->sc_msi_mc);
		}

		/*
		 * Restore command register last to avoid exposing
		 * uninitialised windows.
		 */
		reg = pci_conf_read(pc, tag, PCI_COMMAND_STATUS_REG);
		pci_conf_write(pc, tag, PCI_COMMAND_STATUS_REG,
		    (reg & 0xffff0000) | (sc->sc_csr & 0x0000ffff));

		rv = config_activate_children(self, act);
		break;
	}
	return (rv);
}
Beispiel #14
0
static int
cs4281_pci_attach(device_t dev)
{
    struct sc_info *sc;
    struct ac97_info *codec = NULL;
    u_int32_t data;
    char status[SND_STATUSLEN];

    if ((sc = malloc(sizeof(*sc), M_DEVBUF, M_NOWAIT)) == NULL) {
	device_printf(dev, "cannot allocate softc\n");
	return ENXIO;
    }

    bzero(sc, sizeof(*sc));
    sc->dev = dev;
    sc->type = pci_get_devid(dev);

    data = pci_read_config(dev, PCIR_COMMAND, 2);
    data |= (PCIM_CMD_PORTEN | PCIM_CMD_MEMEN | PCIM_CMD_BUSMASTEREN);
    pci_write_config(dev, PCIR_COMMAND, data, 2);

    data = pci_read_config(dev, PCIR_COMMAND, 2);

#if __FreeBSD_version > 500000
    if (pci_get_powerstate(dev) != PCI_POWERSTATE_D0) {
	/* Reset the power state. */
	device_printf(dev, "chip is in D%d power mode "
		      "-- setting to D0\n", pci_get_powerstate(dev));

	pci_set_powerstate(dev, PCI_POWERSTATE_D0);
    }
#endif
    sc->regid   = PCIR_MAPS;
    sc->regtype = SYS_RES_MEMORY;
    sc->reg = bus_alloc_resource(dev, sc->regtype, &sc->regid,
				 0, ~0, CS4281PCI_BA0_SIZE, RF_ACTIVE);
    if (!sc->reg) {
	sc->regtype = SYS_RES_IOPORT;
	sc->reg = bus_alloc_resource(dev, sc->regtype, &sc->regid,
				     0, ~0, CS4281PCI_BA0_SIZE, RF_ACTIVE);
	if (!sc->reg) {
	    device_printf(dev, "unable to allocate register space\n");
	    goto bad;
	}
    }
    sc->st = rman_get_bustag(sc->reg);
    sc->sh = rman_get_bushandle(sc->reg);

    sc->memid = PCIR_MAPS + 4;
    sc->mem = bus_alloc_resource(dev, SYS_RES_MEMORY, &sc->memid, 0,
				 ~0, CS4281PCI_BA1_SIZE, RF_ACTIVE);
    if (sc->mem == NULL) {
	device_printf(dev, "unable to allocate fifo space\n");
	goto bad;
    }

    sc->irqid = 0;
    sc->irq = bus_alloc_resource(dev, SYS_RES_IRQ, &sc->irqid,
				 0, ~0, 1, RF_ACTIVE | RF_SHAREABLE);
    if (!sc->irq) {
	device_printf(dev, "unable to allocate interrupt\n");
	goto bad;
    }

    if (bus_setup_intr(dev, sc->irq, INTR_TYPE_TTY, cs4281_intr, sc, &sc->ih)) {
	device_printf(dev, "unable to setup interrupt\n");
	goto bad;
    }

    if (bus_dma_tag_create(/*parent*/NULL, /*alignment*/2, /*boundary*/0,
			   /*lowaddr*/BUS_SPACE_MAXADDR_32BIT,
			   /*highaddr*/BUS_SPACE_MAXADDR,
			   /*filter*/NULL, /*filterarg*/NULL,
			   /*maxsize*/CS4281_BUFFER_SIZE, /*nsegments*/1,
			   /*maxsegz*/0x3ffff,
			   /*flags*/0, &sc->parent_dmat) != 0) {
	device_printf(dev, "unable to create dma tag\n");
	goto bad;
    }

    /* power up */
    cs4281_power(sc, 0);

    /* init chip */
    if (cs4281_init(sc) == -1) {
	device_printf(dev, "unable to initialize the card\n");
	goto bad;
    }

    /* create/init mixer */
    codec = AC97_CREATE(dev, sc, cs4281_ac97);
    if (codec == NULL)
        goto bad;

    mixer_init(dev, ac97_getmixerclass(), codec);

    if (pcm_register(dev, sc, 1, 1))
	goto bad;

    pcm_addchan(dev, PCMDIR_PLAY, &cs4281chan_class, sc);
    pcm_addchan(dev, PCMDIR_REC, &cs4281chan_class, sc);

    snprintf(status, SND_STATUSLEN, "at %s 0x%lx irq %ld",
	     (sc->regtype == SYS_RES_IOPORT)? "io" : "memory",
	     rman_get_start(sc->reg), rman_get_start(sc->irq));
    pcm_setstatus(dev, status);

    return 0;

 bad:
    if (codec)
	ac97_destroy(codec);
    if (sc->reg)
	bus_release_resource(dev, sc->regtype, sc->regid, sc->reg);
    if (sc->mem)
	bus_release_resource(dev, SYS_RES_MEMORY, sc->memid, sc->mem);
    if (sc->ih)
	bus_teardown_intr(dev, sc->irq, sc->ih);
    if (sc->irq)
	bus_release_resource(dev, SYS_RES_IRQ, sc->irqid, sc->irq);
    if (sc->parent_dmat)
	bus_dma_tag_destroy(sc->parent_dmat);
    free(sc, M_DEVBUF);

    return ENXIO;
}