Esempio n. 1
0
static void
write_av9110(lmc_softc_t *sc, u_int32_t n, u_int32_t m, u_int32_t v,
	     u_int32_t x, u_int32_t r)
{
	int i;

#if 0
	printf(LMC_PRINTF_FMT ": speed %u, %d %d %d %d %d\n",
	       LMC_PRINTF_ARGS, sc->ictl.clock_rate,
	       n, m, v, x, r);
#endif

        sc->lmc_gpio |= LMC_GEP_SSI_GENERATOR;
	sc->lmc_gpio &= ~(LMC_GEP_SERIAL | LMC_GEP_SERIALCLK);
	LMC_CSR_WRITE(sc, csr_gp, sc->lmc_gpio);

	/*
	 * Set the TXCLOCK, GENERATOR, SERIAL, and SERIALCLK
	 * as outputs.
	 */
	lmc_gpio_mkoutput(sc, (LMC_GEP_SERIAL | LMC_GEP_SERIALCLK
                               | LMC_GEP_SSI_GENERATOR));

        sc->lmc_gpio &= ~(LMC_GEP_SSI_GENERATOR);
	LMC_CSR_WRITE(sc, csr_gp, sc->lmc_gpio);

	/*
	 * a shifting we will go...
	 */
	for (i = 0 ; i < 7 ; i++)
		write_av9110_bit(sc, n >> i);
	for (i = 0 ; i < 7 ; i++)
		write_av9110_bit(sc, m >> i);
	for (i = 0 ; i < 1 ; i++)
		write_av9110_bit(sc, v >> i);
	for (i = 0 ; i < 2 ; i++)
		write_av9110_bit(sc, x >> i);
	for (i = 0 ; i < 2 ; i++)
		write_av9110_bit(sc, r >> i);
	for (i = 0 ; i < 5 ; i++)
		write_av9110_bit(sc, 0x17 >> i);

	/*
	 * stop driving serial-related signals
	 */
	lmc_gpio_mkinput(sc,
			 (LMC_GEP_SERIAL | LMC_GEP_SERIALCLK
                          | LMC_GEP_SSI_GENERATOR));
}
Esempio n. 2
0
void
lmc_reset(lmc_softc_t * const sc)
{
	sc->lmc_miireg16 |= LMC_MII16_FIFO_RESET;
	lmc_mii_writereg(sc, 0, 16, sc->lmc_miireg16);

	sc->lmc_miireg16 &= ~LMC_MII16_FIFO_RESET;
	lmc_mii_writereg(sc, 0, 16, sc->lmc_miireg16);

	/*
	 * make some of the GPIO pins be outputs
	 */
	lmc_gpio_mkoutput(sc, LMC_GEP_DP | LMC_GEP_RESET);

	/*
	 * drive DP and RESET low to force configuration.  This also forces
	 * the transmitter clock to be internal, but we expect to reset
	 * that later anyway.
	 */
	sc->lmc_gpio &= ~(LMC_GEP_DP | LMC_GEP_RESET);
	LMC_CSR_WRITE(sc, csr_gp, sc->lmc_gpio);

	/*
	 * hold for more than 10 microseconds
	 */
	DELAY(50);

	/*
	 * stop driving Xilinx-related signals
	 */
	lmc_gpio_mkinput(sc, LMC_GEP_DP | LMC_GEP_RESET);

	/*
	 * busy wait for the chip to reset
	 */
	while ((LMC_CSR_READ(sc, csr_gp) & LMC_GEP_DP) == 0);

	/*
	 * Call media specific init routine
	 */
	sc->lmc_media->init(sc);
}
int lmc_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) 
{
    lmc_softc_t *sc = dev_to_sc(dev);
    lmc_ctl_t ctl;
    int ret = -EOPNOTSUPP;
    u16 regVal;
    unsigned long flags;

    lmc_trace(dev, "lmc_ioctl in");


    switch (cmd) {
    case LMCIOCGINFO: 
	if (copy_to_user(ifr->ifr_data, &sc->ictl, sizeof(lmc_ctl_t)))
		ret = -EFAULT;
	else
		ret = 0;
        break;

    case LMCIOCSINFO: 
        if (!capable(CAP_NET_ADMIN)) {
            ret = -EPERM;
            break;
        }

        if(dev->flags & IFF_UP){
            ret = -EBUSY;
            break;
        }

	if (copy_from_user(&ctl, ifr->ifr_data, sizeof(lmc_ctl_t))) {
		ret = -EFAULT;
		break;
	}

	spin_lock_irqsave(&sc->lmc_lock, flags);
        sc->lmc_media->set_status (sc, &ctl);

        if(ctl.crc_length != sc->ictl.crc_length) {
            sc->lmc_media->set_crc_length(sc, ctl.crc_length);
	    if (sc->ictl.crc_length == LMC_CTL_CRC_LENGTH_16)
		sc->TxDescriptControlInit |=  LMC_TDES_ADD_CRC_DISABLE;
	    else
		sc->TxDescriptControlInit &= ~LMC_TDES_ADD_CRC_DISABLE;
        }
	spin_unlock_irqrestore(&sc->lmc_lock, flags);

        ret = 0;
        break;

    case LMCIOCIFTYPE: 
        {
	    u16 old_type = sc->if_type;
	    u16	new_type;

	    if (!capable(CAP_NET_ADMIN)) {
		ret = -EPERM;
		break;
	    }

	    if (copy_from_user(&new_type, ifr->ifr_data, sizeof(u16))) {
		ret = -EFAULT;
		break;
	    }

            
	    if (new_type == old_type)
	    {
		ret = 0 ;
		break;				
            }
            
	    spin_lock_irqsave(&sc->lmc_lock, flags);
            lmc_proto_close(sc);

            sc->if_type = new_type;
            lmc_proto_attach(sc);
	    ret = lmc_proto_open(sc);
	    spin_unlock_irqrestore(&sc->lmc_lock, flags);
	    break;
	}

    case LMCIOCGETXINFO: 
	spin_lock_irqsave(&sc->lmc_lock, flags);
        sc->lmc_xinfo.Magic0 = 0xBEEFCAFE;

        sc->lmc_xinfo.PciCardType = sc->lmc_cardtype;
        sc->lmc_xinfo.PciSlotNumber = 0;
        sc->lmc_xinfo.DriverMajorVersion = DRIVER_MAJOR_VERSION;
        sc->lmc_xinfo.DriverMinorVersion = DRIVER_MINOR_VERSION;
        sc->lmc_xinfo.DriverSubVersion = DRIVER_SUB_VERSION;
        sc->lmc_xinfo.XilinxRevisionNumber =
            lmc_mii_readreg (sc, 0, 3) & 0xf;
        sc->lmc_xinfo.MaxFrameSize = LMC_PKT_BUF_SZ;
        sc->lmc_xinfo.link_status = sc->lmc_media->get_link_status (sc);
        sc->lmc_xinfo.mii_reg16 = lmc_mii_readreg (sc, 0, 16);
	spin_unlock_irqrestore(&sc->lmc_lock, flags);

        sc->lmc_xinfo.Magic1 = 0xDEADBEEF;

        if (copy_to_user(ifr->ifr_data, &sc->lmc_xinfo,
			 sizeof(struct lmc_xinfo)))
		ret = -EFAULT;
	else
		ret = 0;

        break;

    case LMCIOCGETLMCSTATS:
	    spin_lock_irqsave(&sc->lmc_lock, flags);
	    if (sc->lmc_cardtype == LMC_CARDTYPE_T1) {
		    lmc_mii_writereg(sc, 0, 17, T1FRAMER_FERR_LSB);
		    sc->extra_stats.framingBitErrorCount +=
			    lmc_mii_readreg(sc, 0, 18) & 0xff;
		    lmc_mii_writereg(sc, 0, 17, T1FRAMER_FERR_MSB);
		    sc->extra_stats.framingBitErrorCount +=
			    (lmc_mii_readreg(sc, 0, 18) & 0xff) << 8;
		    lmc_mii_writereg(sc, 0, 17, T1FRAMER_LCV_LSB);
		    sc->extra_stats.lineCodeViolationCount +=
			    lmc_mii_readreg(sc, 0, 18) & 0xff;
		    lmc_mii_writereg(sc, 0, 17, T1FRAMER_LCV_MSB);
		    sc->extra_stats.lineCodeViolationCount +=
			    (lmc_mii_readreg(sc, 0, 18) & 0xff) << 8;
		    lmc_mii_writereg(sc, 0, 17, T1FRAMER_AERR);
		    regVal = lmc_mii_readreg(sc, 0, 18) & 0xff;

		    sc->extra_stats.lossOfFrameCount +=
			    (regVal & T1FRAMER_LOF_MASK) >> 4;
		    sc->extra_stats.changeOfFrameAlignmentCount +=
			    (regVal & T1FRAMER_COFA_MASK) >> 2;
		    sc->extra_stats.severelyErroredFrameCount +=
			    regVal & T1FRAMER_SEF_MASK;
	    }
	    spin_unlock_irqrestore(&sc->lmc_lock, flags);
	    if (copy_to_user(ifr->ifr_data, &sc->lmc_device->stats,
			     sizeof(sc->lmc_device->stats)) ||
		copy_to_user(ifr->ifr_data + sizeof(sc->lmc_device->stats),
			     &sc->extra_stats, sizeof(sc->extra_stats)))
		    ret = -EFAULT;
	    else
		    ret = 0;
	    break;

    case LMCIOCCLEARLMCSTATS:
	    if (!capable(CAP_NET_ADMIN)) {
		    ret = -EPERM;
		    break;
	    }

	    spin_lock_irqsave(&sc->lmc_lock, flags);
	    memset(&sc->lmc_device->stats, 0, sizeof(sc->lmc_device->stats));
	    memset(&sc->extra_stats, 0, sizeof(sc->extra_stats));
	    sc->extra_stats.check = STATCHECK;
	    sc->extra_stats.version_size = (DRIVER_VERSION << 16) +
		    sizeof(sc->lmc_device->stats) + sizeof(sc->extra_stats);
	    sc->extra_stats.lmc_cardtype = sc->lmc_cardtype;
	    spin_unlock_irqrestore(&sc->lmc_lock, flags);
	    ret = 0;
	    break;

    case LMCIOCSETCIRCUIT: 
        if (!capable(CAP_NET_ADMIN)){
            ret = -EPERM;
            break;
        }

        if(dev->flags & IFF_UP){
            ret = -EBUSY;
            break;
        }

	if (copy_from_user(&ctl, ifr->ifr_data, sizeof(lmc_ctl_t))) {
		ret = -EFAULT;
		break;
	}
	spin_lock_irqsave(&sc->lmc_lock, flags);
        sc->lmc_media->set_circuit_type(sc, ctl.circuit_type);
        sc->ictl.circuit_type = ctl.circuit_type;
	spin_unlock_irqrestore(&sc->lmc_lock, flags);
        ret = 0;

        break;

    case LMCIOCRESET: 
        if (!capable(CAP_NET_ADMIN)){
            ret = -EPERM;
            break;
        }

	spin_lock_irqsave(&sc->lmc_lock, flags);
        
        printk (" REG16 before reset +%04x\n", lmc_mii_readreg (sc, 0, 16));
        lmc_running_reset (dev);
        printk (" REG16 after reset +%04x\n", lmc_mii_readreg (sc, 0, 16));

        LMC_EVENT_LOG(LMC_EVENT_FORCEDRESET, LMC_CSR_READ (sc, csr_status), lmc_mii_readreg (sc, 0, 16));
	spin_unlock_irqrestore(&sc->lmc_lock, flags);

        ret = 0;
        break;

#ifdef DEBUG
    case LMCIOCDUMPEVENTLOG:
	if (copy_to_user(ifr->ifr_data, &lmcEventLogIndex, sizeof(u32))) {
		ret = -EFAULT;
		break;
	}
	if (copy_to_user(ifr->ifr_data + sizeof(u32), lmcEventLogBuf,
			 sizeof(lmcEventLogBuf)))
		ret = -EFAULT;
	else
		ret = 0;

        break;
#endif 
    case LMCIOCT1CONTROL: 
        if (sc->lmc_cardtype != LMC_CARDTYPE_T1){
            ret = -EOPNOTSUPP;
            break;
        }
        break;
    case LMCIOCXILINX: 
        {
            struct lmc_xilinx_control xc; 

            if (!capable(CAP_NET_ADMIN)){
                ret = -EPERM;
                break;
            }

            netif_stop_queue(dev);

	    if (copy_from_user(&xc, ifr->ifr_data, sizeof(struct lmc_xilinx_control))) {
		ret = -EFAULT;
		break;
	    }
            switch(xc.command){
            case lmc_xilinx_reset: 
                {
                    u16 mii;
		    spin_lock_irqsave(&sc->lmc_lock, flags);
                    mii = lmc_mii_readreg (sc, 0, 16);

                    lmc_gpio_mkinput(sc, 0xff);

                    lmc_gpio_mkoutput(sc, LMC_GEP_RESET);


                    sc->lmc_gpio &= ~LMC_GEP_RESET;
                    LMC_CSR_WRITE(sc, csr_gp, sc->lmc_gpio);


                    udelay(50);

                    sc->lmc_gpio |= LMC_GEP_RESET;
                    LMC_CSR_WRITE(sc, csr_gp, sc->lmc_gpio);


                    lmc_gpio_mkinput(sc, 0xff);

                    
                    sc->lmc_media->set_link_status (sc, 1);
                    sc->lmc_media->set_status (sc, NULL);

                    {
                        int i;
                        for(i = 0; i < 5; i++){
                            lmc_led_on(sc, LMC_DS3_LED0);
                            mdelay(100);
                            lmc_led_off(sc, LMC_DS3_LED0);
                            lmc_led_on(sc, LMC_DS3_LED1);
                            mdelay(100);
                            lmc_led_off(sc, LMC_DS3_LED1);
                            lmc_led_on(sc, LMC_DS3_LED3);
                            mdelay(100);
                            lmc_led_off(sc, LMC_DS3_LED3);
                            lmc_led_on(sc, LMC_DS3_LED2);
                            mdelay(100);
                            lmc_led_off(sc, LMC_DS3_LED2);
                        }
                    }
		    spin_unlock_irqrestore(&sc->lmc_lock, flags);
                    
                    

                    ret = 0x0;

                }

                break;
            case lmc_xilinx_load_prom: 
                {
                    u16 mii;
                    int timeout = 500000;
		    spin_lock_irqsave(&sc->lmc_lock, flags);
                    mii = lmc_mii_readreg (sc, 0, 16);

                    lmc_gpio_mkinput(sc, 0xff);

                    lmc_gpio_mkoutput(sc,  LMC_GEP_DP | LMC_GEP_RESET);


                    sc->lmc_gpio &= ~(LMC_GEP_RESET | LMC_GEP_DP);
                    LMC_CSR_WRITE(sc, csr_gp, sc->lmc_gpio);


                    udelay(50);

                    sc->lmc_gpio |= LMC_GEP_DP | LMC_GEP_RESET;
                    LMC_CSR_WRITE(sc, csr_gp, sc->lmc_gpio);

                    while( (LMC_CSR_READ(sc, csr_gp) & LMC_GEP_INIT) == 0 &&
                           (timeout-- > 0))
                        cpu_relax();


                    lmc_gpio_mkinput(sc, 0xff);
		    spin_unlock_irqrestore(&sc->lmc_lock, flags);

                    ret = 0x0;
                    

                    break;

                }

            case lmc_xilinx_load: 
                {
                    char *data;
                    int pos;
                    int timeout = 500000;

                    if (!xc.data) {
                            ret = -EINVAL;
                            break;
                    }

                    data = kmalloc(xc.len, GFP_KERNEL);
                    if (!data) {
                            ret = -ENOMEM;
                            break;
                    }
                    
                    if(copy_from_user(data, xc.data, xc.len))
                    {
                    	kfree(data);
                    	ret = -ENOMEM;
                    	break;
                    }

                    printk("%s: Starting load of data Len: %d at 0x%p == 0x%p\n", dev->name, xc.len, xc.data, data);

		    spin_lock_irqsave(&sc->lmc_lock, flags);
                    lmc_gpio_mkinput(sc, 0xff);


                    sc->lmc_gpio = 0x00;
                    sc->lmc_gpio &= ~LMC_GEP_DP;
                    sc->lmc_gpio &= ~LMC_GEP_RESET;
                    sc->lmc_gpio |=  LMC_GEP_MODE;
                    LMC_CSR_WRITE(sc, csr_gp, sc->lmc_gpio);

                    lmc_gpio_mkoutput(sc, LMC_GEP_MODE | LMC_GEP_DP | LMC_GEP_RESET);

                    udelay(50);

                    lmc_gpio_mkinput(sc, LMC_GEP_DP | LMC_GEP_RESET);

                    sc->lmc_gpio = 0x00;
                    sc->lmc_gpio |= LMC_GEP_MODE;
                    sc->lmc_gpio |= LMC_GEP_DATA;
                    sc->lmc_gpio |= LMC_GEP_CLK;
                    LMC_CSR_WRITE(sc, csr_gp, sc->lmc_gpio);
                    
                    lmc_gpio_mkoutput(sc, LMC_GEP_DATA | LMC_GEP_CLK | LMC_GEP_MODE );

                    while( (LMC_CSR_READ(sc, csr_gp) & LMC_GEP_INIT) == 0 &&
                           (timeout-- > 0))
                        cpu_relax();

                    printk(KERN_DEBUG "%s: Waited %d for the Xilinx to clear it's memory\n", dev->name, 500000-timeout);

                    for(pos = 0; pos < xc.len; pos++){
                        switch(data[pos]){
                        case 0:
                            sc->lmc_gpio &= ~LMC_GEP_DATA; 
                            break;
                        case 1:
                            sc->lmc_gpio |= LMC_GEP_DATA; 
                            break;
                        default:
                            printk(KERN_WARNING "%s Bad data in xilinx programming data at %d, got %d wanted 0 or 1\n", dev->name, pos, data[pos]);
                            sc->lmc_gpio |= LMC_GEP_DATA; 
                        }
                        sc->lmc_gpio &= ~LMC_GEP_CLK; 
                        sc->lmc_gpio |= LMC_GEP_MODE;
                        LMC_CSR_WRITE(sc, csr_gp, sc->lmc_gpio);
                        udelay(1);
                        
                        sc->lmc_gpio |= LMC_GEP_CLK; 
                        sc->lmc_gpio |= LMC_GEP_MODE;
                        LMC_CSR_WRITE(sc, csr_gp, sc->lmc_gpio);
                        udelay(1);
                    }
                    if((LMC_CSR_READ(sc, csr_gp) & LMC_GEP_INIT) == 0){
                        printk(KERN_WARNING "%s: Reprogramming FAILED. Needs to be reprogrammed. (corrupted data)\n", dev->name);
                    }
                    else if((LMC_CSR_READ(sc, csr_gp) & LMC_GEP_DP) == 0){
                        printk(KERN_WARNING "%s: Reprogramming FAILED. Needs to be reprogrammed. (done)\n", dev->name);
                    }
                    else {
                        printk(KERN_DEBUG "%s: Done reprogramming Xilinx, %d bits, good luck!\n", dev->name, pos);
                    }

                    lmc_gpio_mkinput(sc, 0xff);
                    
                    sc->lmc_miireg16 |= LMC_MII16_FIFO_RESET;
                    lmc_mii_writereg(sc, 0, 16, sc->lmc_miireg16);

                    sc->lmc_miireg16 &= ~LMC_MII16_FIFO_RESET;
                    lmc_mii_writereg(sc, 0, 16, sc->lmc_miireg16);
		    spin_unlock_irqrestore(&sc->lmc_lock, flags);

                    kfree(data);
                    
                    ret = 0;
                    
                    break;
                }
            default: 
                ret = -EBADE;
                break;
            }

            netif_wake_queue(dev);
            sc->lmc_txfull = 0;

        }
        break;
    default: 
        
        ret = lmc_proto_ioctl (sc, ifr, cmd);
        break;
    }
Esempio n. 4
0
static void
lmc_pci_attach(struct device * const parent,
		struct device * const self, void * const aux)
{
	u_int32_t revinfo, cfdainfo, id, ssid;
	pci_intr_handle_t intrhandle;
	const char *intrstr;
	unsigned csroffset = LMC_PCI_CSROFFSET;
	unsigned csrsize = LMC_PCI_CSRSIZE;
	lmc_csrptr_t csr_base;
	lmc_spl_t s;
	lmc_intrfunc_t (*intr_rtn)(void *) = lmc_intr_normal;
	lmc_softc_t * const sc = (lmc_softc_t *) self;
	struct pci_attach_args * const pa = (struct pci_attach_args *) aux;
	extern lmc_media_t lmc_hssi_media;
	extern lmc_media_t lmc_ds3_media;
	extern lmc_media_t lmc_t1_media;
	extern lmc_media_t lmc_ssi_media;

	revinfo  = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_CFRV) & 0xFF;
	id       = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_CFID);
	cfdainfo = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_CFDA);
	ssid = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_SSID);

	switch (PCI_CHIPID(ssid)) {
	case PCI_PRODUCT_LMC_HSSI:
		printf(": HSSI\n");
		sc->lmc_media = &lmc_hssi_media;
		break;
	case PCI_PRODUCT_LMC_HSSIC:
		printf(": HSSIc\n");
		sc->lmc_media = &lmc_hssi_media;
		break;
	case PCI_PRODUCT_LMC_DS3:
		printf(": DS3\n");
		sc->lmc_media = &lmc_ds3_media;
		break;
	case PCI_PRODUCT_LMC_SSI:
		printf(": SSI\n");
		sc->lmc_media = &lmc_ssi_media;
		break;
	case PCI_PRODUCT_LMC_DS1:
		printf(": T1\n");
		sc->lmc_media = &lmc_t1_media;
		break;
	}

        sc->lmc_pci_busno = parent;
        sc->lmc_pci_devno = pa->pa_device;

	sc->lmc_chipid = LMC_21140A;
	sc->lmc_features |= LMC_HAVE_STOREFWD;
	if (sc->lmc_chipid == LMC_21140A && revinfo <= 0x22)
		sc->lmc_features |= LMC_HAVE_RXBADOVRFLW;

	if (cfdainfo & (TULIP_CFDA_SLEEP | TULIP_CFDA_SNOOZE)) {
		cfdainfo &= ~(TULIP_CFDA_SLEEP | TULIP_CFDA_SNOOZE);
		pci_conf_write(pa->pa_pc, pa->pa_tag, PCI_CFDA, cfdainfo);
		DELAY(11 * 1000);
	}

	bcopy(self->dv_xname, sc->lmc_if.if_xname, IFNAMSIZ);
	sc->lmc_if.if_softc = sc;
	sc->lmc_pc = pa->pa_pc;

	sc->lmc_revinfo = revinfo;
	sc->lmc_if.if_softc = sc;

	csr_base = 0;
	{
		bus_space_tag_t iot, memt;
		bus_space_handle_t ioh, memh;
		int ioh_valid, memh_valid;

		ioh_valid = (pci_mapreg_map(pa, PCI_CBIO, PCI_MAPREG_TYPE_IO,
		    0, &iot, &ioh, NULL, NULL, 0) == 0);
		memh_valid = (pci_mapreg_map(pa, PCI_CBMA,
		    PCI_MAPREG_TYPE_MEM | PCI_MAPREG_MEM_TYPE_32BIT, 0, &memt,
		    &memh, NULL, NULL, 0) == 0);

		if (memh_valid) {
			sc->lmc_bustag = memt;
			sc->lmc_bushandle = memh;
		} else if (ioh_valid) {
			sc->lmc_bustag = iot;
			sc->lmc_bushandle = ioh;
		} else {
			printf("%s: unable to map device registers\n",
			       sc->lmc_dev.dv_xname);
			return;
		}
	}

	sc->lmc_dmatag = pa->pa_dmat;
	if ((lmc_busdma_init(sc)) != 0) {
		printf("error initing bus_dma\n");
		return;
	}

	lmc_initcsrs(sc, csr_base + csroffset, csrsize);
	lmc_initring(sc, &sc->lmc_rxinfo, sc->lmc_rxdescs,
		       LMC_RXDESCS);
	lmc_initring(sc, &sc->lmc_txinfo, sc->lmc_txdescs,
		       LMC_TXDESCS);

	lmc_gpio_mkinput(sc, 0xff);
	sc->lmc_gpio = 0;  /* drive no signals yet */

	sc->lmc_media->defaults(sc);

	sc->lmc_media->set_link_status(sc, LMC_LINK_DOWN); /* down */

	/*
	 * Make sure there won't be any interrupts or such...
	 */
	LMC_CSR_WRITE(sc, csr_busmode, TULIP_BUSMODE_SWRESET);

	/*
	 * Wait 10 microseconds (actually 50 PCI cycles but at 
	 * 33MHz that comes to two microseconds but wait a
	 * bit longer anyways)
	 */
	DELAY(100);

	lmc_read_macaddr(sc);

        if (pci_intr_map(pa, &intrhandle)) {
		 printf("%s: couldn't map interrupt\n",
			sc->lmc_dev.dv_xname);
		return;
	}
	intrstr = pci_intr_string(pa->pa_pc, intrhandle);

	sc->lmc_ih = pci_intr_establish(pa->pa_pc, intrhandle, IPL_NET,
						intr_rtn, sc, self->dv_xname);

	if (sc->lmc_ih == NULL) {
		printf("%s: couldn't establish interrupt",
		       sc->lmc_dev.dv_xname);
		if (intrstr != NULL)
			printf(" at %s", intrstr);
		printf("\n");
		return;
	}

        printf("%s: pass %d.%d, serial " LMC_EADDR_FMT ", %s\n",
               sc->lmc_dev.dv_xname,
               (sc->lmc_revinfo & 0xF0) >> 4, sc->lmc_revinfo & 0x0F,
               LMC_EADDR_ARGS(sc->lmc_enaddr), intrstr);

        sc->lmc_ats = shutdownhook_establish(lmc_shutdown, sc);
        if (sc->lmc_ats == NULL)
		printf("%s: warning: couldn't establish shutdown hook\n",
		       sc->lmc_xname);

	s = LMC_RAISESPL();
	lmc_dec_reset(sc);
	lmc_reset(sc);
	lmc_attach(sc);
	LMC_RESTORESPL(s);
}