/* . Function: smc_halt . Purpose: closes down the SMC91xxx chip. . Method: . 1. zero the interrupt mask . 2. clear the enable receive flag . 3. clear the enable xmit flags . . TODO: . (1) maybe utilize power down mode. . Why not yet? Because while the chip will go into power down mode, . the manual says that it will wake up in response to any I/O requests . in the register space. Empirical results do not show this working. */ static void smc_halt(struct eth_device *dev) { PRINTK2("%s: smc_halt\n", SMC_DEV_NAME); /* no more interrupts for me */ SMC_SELECT_BANK( dev, 2 ); SMC_outb( dev, 0, IM_REG ); /* and tell the card to stay away from that nasty outside world */ SMC_SELECT_BANK( dev, 0 ); SMC_outb( dev, RCR_CLEAR, RCR_REG ); SMC_outb( dev, TCR_CLEAR, TCR_REG ); swap_to(FLASH); }
/* . Function: smc_shutdown . Purpose: closes down the SMC91xxx chip. . Method: . 1. zero the interrupt mask . 2. clear the enable receive flag . 3. clear the enable xmit flags . . TODO: . (1) maybe utilize power down mode. . Why not yet? Because while the chip will go into power down mode, . the manual says that it will wake up in response to any I/O requests . in the register space. Empirical results do not show this working. */ static void smc_shutdown() { PRINTK2(CARDNAME ": smc_shutdown\n"); /* no more interrupts for me */ SMC_SELECT_BANK( 2 ); SMC_outb( 0, IM_REG ); /* and tell the card to stay away from that nasty outside world */ SMC_SELECT_BANK( 0 ); SMC_outb( RCR_CLEAR, RCR_REG ); SMC_outb( TCR_CLEAR, TCR_REG ); #ifdef SHARED_RESOURCES swap_to(FLASH); #endif }
/* . Function: smc_reset( void ) . Purpose: . This sets the SMC91111 chip to its normal state, hopefully from whatever . mess that any other DOS driver has put it in. . . Maybe I should reset more registers to defaults in here? SOFTRST should . do that for me. . . Method: . 1. send a SOFT RESET . 2. wait for it to finish . 3. enable autorelease mode . 4. reset the memory management unit . 5. clear all interrupts . */ static void smc_reset (struct eth_device *dev) { PRINTK2 ("%s: smc_reset\n", SMC_DEV_NAME); /* This resets the registers mostly to defaults, but doesn't affect EEPROM. That seems unnecessary */ SMC_SELECT_BANK (dev, 0); SMC_outw (dev, RCR_SOFTRST, RCR_REG); /* Setup the Configuration Register */ /* This is necessary because the CONFIG_REG is not affected */ /* by a soft reset */ SMC_SELECT_BANK (dev, 1); #if defined(CONFIG_SMC91111_EXT_PHY) SMC_outw (dev, CONFIG_DEFAULT | CONFIG_EXT_PHY, CONFIG_REG); #else SMC_outw (dev, CONFIG_DEFAULT, CONFIG_REG); #endif /* Release from possible power-down state */ /* Configuration register is not affected by Soft Reset */ SMC_outw (dev, SMC_inw (dev, CONFIG_REG) | CONFIG_EPH_POWER_EN, CONFIG_REG); SMC_SELECT_BANK (dev, 0); /* this should pause enough for the chip to be happy */ udelay (10); /* Disable transmit and receive functionality */ SMC_outw (dev, RCR_CLEAR, RCR_REG); SMC_outw (dev, TCR_CLEAR, TCR_REG); /* set the control register */ SMC_SELECT_BANK (dev, 1); SMC_outw (dev, CTL_DEFAULT, CTL_REG); /* Reset the MMU */ SMC_SELECT_BANK (dev, 2); smc_wait_mmu_release_complete (dev); SMC_outw (dev, MC_RESET, MMU_CMD_REG); while (SMC_inw (dev, MMU_CMD_REG) & MC_BUSY) udelay (1); /* Wait until not busy */ /* Note: It doesn't seem that waiting for the MMU busy is needed here, but this is a place where future chipsets _COULD_ break. Be wary of issuing another MMU command right after this */ /* Disable all interrupts */ SMC_outb (dev, 0, IM_REG); }
/* . Function: smc_send(struct net_device * ) . Purpose: . This sends the actual packet to the SMC9xxx chip. . . Algorithm: . First, see if a saved_skb is available. . ( this should NOT be called if there is no 'saved_skb' . Now, find the packet number that the chip allocated . Point the data pointers at it in memory . Set the length word in the chip's memory . Dump the packet to chip memory . Check if a last byte is needed ( odd length packet ) . if so, set the control flag right . Tell the card to send it . Enable the transmit interrupt, so I know if it failed . Free the kernel data if I actually sent it. */ static int smc_send(struct eth_device *dev, void *packet, int packet_length) { byte packet_no; byte *buf; int length; int numPages; int try = 0; int time_out; byte status; byte saved_pnr; word saved_ptr; /* save PTR and PNR registers before manipulation */ SMC_SELECT_BANK (dev, 2); saved_pnr = SMC_inb( dev, PN_REG ); saved_ptr = SMC_inw( dev, PTR_REG ); PRINTK3 ("%s: smc_hardware_send_packet\n", SMC_DEV_NAME); length = ETH_ZLEN < packet_length ? packet_length : ETH_ZLEN; /* allocate memory ** The MMU wants the number of pages to be the number of 256 bytes ** 'pages', minus 1 ( since a packet can't ever have 0 pages :) ) ** ** The 91C111 ignores the size bits, but the code is left intact ** for backwards and future compatibility. ** ** Pkt size for allocating is data length +6 (for additional status ** words, length and ctl!) ** ** If odd size then last byte is included in this header. */ numPages = ((length & 0xfffe) + 6); numPages >>= 8; /* Divide by 256 */ if (numPages > 7) { printf ("%s: Far too big packet error. \n", SMC_DEV_NAME); return 0; } /* now, try to allocate the memory */ SMC_SELECT_BANK (dev, 2); SMC_outw (dev, MC_ALLOC | numPages, MMU_CMD_REG); /* FIXME: the ALLOC_INT bit never gets set * * so the following will always give a * * memory allocation error. * * same code works in armboot though * * -ro */ again: try++; time_out = MEMORY_WAIT_TIME; do { status = SMC_inb (dev, SMC91111_INT_REG); if (status & IM_ALLOC_INT) { /* acknowledge the interrupt */ SMC_outb (dev, IM_ALLOC_INT, SMC91111_INT_REG); break; } } while (--time_out); if (!time_out) { PRINTK2 ("%s: memory allocation, try %d failed ...\n", SMC_DEV_NAME, try); if (try < SMC_ALLOC_MAX_TRY) goto again; else return 0; }