static void init_82586_mem(struct net_device *dev) { struct net_local *lp = (struct net_local *)dev->priv; short ioaddr = dev->base_addr; unsigned long shmem = dev->mem_start; /* Enable loopback to protect the wire while starting up, and hold the 586 in reset during the memory initialization. */ outb(0x20, ioaddr + MISC_CTRL); /* Fix the ISCP address and base. */ init_words[3] = SCB_BASE; init_words[7] = SCB_BASE; /* Write the words at 0xfff6 (address-aliased to 0xfffff6). */ isa_memcpy_toio(dev->mem_end-10, init_words, 10); /* Write the words at 0x0000. */ isa_memcpy_toio(dev->mem_start, init_words + 5, sizeof(init_words) - 10); /* Fill in the station address. */ isa_memcpy_toio(dev->mem_start+SA_OFFSET, dev->dev_addr, sizeof(dev->dev_addr)); /* The Tx-block list is written as needed. We just set up the values. */ lp->tx_cmd_link = IDLELOOP + 4; lp->tx_head = lp->tx_reap = TX_BUF_START; init_rx_bufs(dev); /* Start the 586 by releasing the reset line, but leave loopback. */ outb(0xA0, ioaddr + MISC_CTRL); /* This was time consuming to track down: you need to give two channel attention signals to reliably start up the i82586. */ outb(0, ioaddr + SIGNAL_CA); { int boguscnt = 50; while (isa_readw(shmem+iSCB_STATUS) == 0) if (--boguscnt == 0) { printk("%s: i82586 initialization timed out with status %04x," "cmd %04x.\n", dev->name, isa_readw(shmem+iSCB_STATUS), isa_readw(shmem+iSCB_CMD)); break; } /* Issue channel-attn -- the 82586 won't start. */ outb(0, ioaddr + SIGNAL_CA); } /* Disable loopback and enable interrupts. */ outb(0x84, ioaddr + MISC_CTRL); if (net_debug > 4) printk("%s: Initialized 82586, status %04x.\n", dev->name, isa_readw(shmem+iSCB_STATUS)); return; }
int msnd_fifo_read(msnd_fifo *f, char *buf, size_t len) { int count = 0; while ((count < len) && (f->len > 0)) { int nread; if (f->tail <= f->head) { nread = len - count; if (nread > f->n - f->head) nread = f->n - f->head; } else { nread = f->tail - f->head; if (nread > len - count) nread = len - count; } isa_memcpy_toio((unsigned long) buf, f->data + f->head, nread); count += nread; buf += nread; f->len -= nread; f->head += nread; f->head %= f->n; } return count; }
static void ultramca_block_output(struct net_device *dev, int count, const unsigned char *buf, int start_page) { unsigned long shmem = dev->mem_start + ((start_page - START_PG) << 8); isa_memcpy_toio(shmem, buf, count); }
static void es_block_output(struct net_device *dev, int count, const unsigned char *buf, int start_page) { unsigned long shmem = dev->mem_start + ((start_page - ES_START_PG)<<8); count = (count + 3) & ~3; /* Round up to doubleword */ isa_memcpy_toio(shmem, buf, count); }
static void hpp_mem_block_output(struct net_device *dev, int count, const unsigned char *buf, int start_page) { int ioaddr = dev->base_addr - NIC_OFFSET; int option_reg = inw(ioaddr + HPP_OPTION); outw(start_page << 8, ioaddr + HPP_OUT_ADDR); outw(option_reg & ~(MemDisable + BootROMEnb), ioaddr + HPP_OPTION); isa_memcpy_toio(dev->mem_start, buf, (count + 3) & ~3); outw(option_reg, ioaddr + HPP_OPTION); return; }
static void hardware_send_packet(struct net_device *dev, void *buf, short length) { struct net_local *lp = (struct net_local *)dev->priv; short ioaddr = dev->base_addr; ushort tx_block = lp->tx_head; unsigned long write_ptr = dev->mem_start + tx_block; /* Set the write pointer to the Tx block, and put out the header. */ isa_writew(0x0000,write_ptr); /* Tx status */ isa_writew(CMD_INTR|CmdTx,write_ptr+=2); /* Tx command */ isa_writew(tx_block+16,write_ptr+=2); /* Next command is a NoOp. */ isa_writew(tx_block+8,write_ptr+=2); /* Data Buffer offset. */ /* Output the data buffer descriptor. */ isa_writew(length | 0x8000,write_ptr+=2); /* Byte count parameter. */ isa_writew(-1,write_ptr+=2); /* No next data buffer. */ isa_writew(tx_block+22+SCB_BASE,write_ptr+=2); /* Buffer follows the NoOp command. */ isa_writew(0x0000,write_ptr+=2); /* Buffer address high bits (always zero). */ /* Output the Loop-back NoOp command. */ isa_writew(0x0000,write_ptr+=2); /* Tx status */ isa_writew(CmdNOp,write_ptr+=2); /* Tx command */ isa_writew(tx_block+16,write_ptr+=2); /* Next is myself. */ /* Output the packet at the write pointer. */ isa_memcpy_toio(write_ptr+2, buf, length); /* Set the old command link pointing to this send packet. */ isa_writew(tx_block,dev->mem_start + lp->tx_cmd_link); lp->tx_cmd_link = tx_block + 20; /* Set the next free tx region. */ lp->tx_head = tx_block + TX_BUF_SIZE; if (lp->tx_head > RX_BUF_START - TX_BUF_SIZE) lp->tx_head = TX_BUF_START; if (net_debug > 4) { printk("%s: 3c507 @%x send length = %d, tx_block %3x, next %3x.\n", dev->name, ioaddr, length, tx_block, lp->tx_head); } /* Grimly block further packets if there has been insufficient reaping. */ if (++lp->tx_pkts_in_ring < NUM_TX_BUFS) netif_wake_queue(dev); }
/* * Either use the shared memory (if enabled on the board) or put the packet * out through the ASIC FIFO. */ static void el2_block_output(struct net_device *dev, int count, const unsigned char *buf, int start_page) { unsigned short int *wrd; int boguscount; /* timeout counter */ unsigned short word; /* temporary for better machine code */ if (ei_status.word16) /* Tx packets go into bank 0 on EL2/16 card */ outb(EGACFR_RSEL|EGACFR_TCM, E33G_GACFR); else outb(EGACFR_NORM, E33G_GACFR); if (dev->mem_start) { /* Shared memory transfer */ unsigned long dest_addr = dev->mem_start + ((start_page - ei_status.tx_start_page) << 8); isa_memcpy_toio(dest_addr, buf, count); outb(EGACFR_NORM, E33G_GACFR); /* Back to bank1 in case on bank0 */ return; } /* * No shared memory, put the packet out the other way. * Set up then start the internal memory transfer to Tx Start Page */ word = (unsigned short)start_page; outb(word&0xFF, E33G_DMAAH); outb(word>>8, E33G_DMAAL); outb_p((ei_status.interface_num ? ECNTRL_AUI : ECNTRL_THIN ) | ECNTRL_OUTPUT | ECNTRL_START, E33G_CNTRL); /* * Here I am going to write data to the FIFO as quickly as possible. * Note that E33G_FIFOH is defined incorrectly. It is really * E33G_FIFOL, the lowest port address for both the byte and * word write. Variable 'count' is NOT checked. Caller must supply a * valid count. Note that I may write a harmless extra byte to the * 8390 if the byte-count was not even. */ wrd = (unsigned short int *) buf; count = (count + 1) >> 1; for(;;) { boguscount = 0x1000; while ((inb(E33G_STATUS) & ESTAT_DPRDY) == 0) { if(!boguscount--) { printk("%s: FIFO blocked in el2_block_output.\n", dev->name); el2_reset_8390(dev); goto blocked; } } if(count > WRD_COUNT) { outsw(E33G_FIFOH, wrd, WRD_COUNT); wrd += WRD_COUNT; count -= WRD_COUNT; } else { outsw(E33G_FIFOH, wrd, count); break; } } blocked:; outb_p(ei_status.interface_num==0 ? ECNTRL_THIN : ECNTRL_AUI, E33G_CNTRL); return; }
static int ibmlana_tx(struct sk_buff *skb, struct net_device *dev) { ibmlana_priv *priv = (ibmlana_priv *) dev->priv; int retval = 0, tmplen, addr; unsigned long flags; tda_t tda; int baddr; /* find out if there are free slots for a frame to transmit. If not, the upper layer is in deep desperation and we simply ignore the frame. */ if (priv->txusedcnt >= TXBUFCNT) { retval = -EIO; priv->stat.tx_dropped++; goto tx_done; } /* copy the frame data into the next free transmit buffer - fillup missing */ tmplen = skb->len; if (tmplen < 60) tmplen = 60; baddr = priv->txbufstart + (priv->nexttxdescr * PKTSIZE); isa_memcpy_toio(dev->mem_start + baddr, skb->data, skb->len); /* copy filler into RAM - in case we're filling up... we're filling a bit more than necessary, but that doesn't harm since the buffer is far larger... Sorry Linus for the filler string but I couldn't resist ;-) */ if (tmplen > skb->len) { char *fill = "NetBSD is a nice OS too! "; unsigned int destoffs = skb->len, l = strlen(fill); while (destoffs < tmplen) { isa_memcpy_toio(dev->mem_start + baddr + destoffs, fill, l); destoffs += l; } } /* set up the new frame descriptor */ addr = priv->tdastart + (priv->nexttxdescr * sizeof(tda_t)); isa_memcpy_fromio(&tda, dev->mem_start + addr, sizeof(tda_t)); tda.length = tda.fraglength = tmplen; isa_memcpy_toio(dev->mem_start + addr, &tda, sizeof(tda_t)); /* if there were no active descriptors, trigger the SONIC */ spin_lock_irqsave(&priv->lock, flags); priv->txusedcnt++; priv->txused[priv->nexttxdescr] = 1; /* are all transmission slots used up ? */ if (priv->txusedcnt >= TXBUFCNT) netif_stop_queue(dev); if (priv->txusedcnt == 1) StartTx(dev, priv->nexttxdescr); priv->nexttxdescr = (priv->nexttxdescr + 1) % TXBUFCNT; spin_unlock_irqrestore(&priv->lock, flags); tx_done: dev_kfree_skb(skb); return retval; }
static void irqrx_handler(struct net_device *dev) { ibmlana_priv *priv = (ibmlana_priv *) dev->priv; rda_t rda; u32 rdaaddr, lrdaaddr; /* loop until ... */ while (1) { /* read descriptor that was next to be filled by SONIC */ rdaaddr = priv->rdastart + (priv->nextrxdescr * sizeof(rda_t)); lrdaaddr = priv->rdastart + (priv->lastrxdescr * sizeof(rda_t)); isa_memcpy_fromio(&rda, dev->mem_start + rdaaddr, sizeof(rda_t)); /* iron out upper word halves of fields we use - SONIC will duplicate bits 0..15 to 16..31 */ rda.status &= 0xffff; rda.length &= 0xffff; rda.startlo &= 0xffff; /* stop if the SONIC still owns it, i.e. there is no data for us */ if (rda.inuse) break; /* good packet? */ else if (rda.status & RCREG_PRX) { struct sk_buff *skb; /* fetch buffer */ skb = dev_alloc_skb(rda.length + 2); if (skb == NULL) priv->stat.rx_dropped++; else { /* copy out data */ isa_memcpy_fromio(skb_put(skb, rda.length), dev->mem_start + rda.startlo, rda.length); /* set up skb fields */ skb->dev = dev; skb->protocol = eth_type_trans(skb, dev); skb->ip_summed = CHECKSUM_NONE; /* bookkeeping */ dev->last_rx = jiffies; priv->stat.rx_packets++; priv->stat.rx_bytes += rda.length; /* pass to the upper layers */ netif_rx(skb); } } /* otherwise check error status bits and increase statistics */ else { priv->stat.rx_errors++; if (rda.status & RCREG_FAER) priv->stat.rx_frame_errors++; if (rda.status & RCREG_CRCR) priv->stat.rx_crc_errors++; } /* descriptor processed, will become new last descriptor in queue */ rda.link = 1; rda.inuse = 1; isa_memcpy_toio(dev->mem_start + rdaaddr, &rda, sizeof(rda_t)); /* set up link and EOL = 0 in currently last descriptor. Only write the link field since the SONIC may currently already access the other fields. */ isa_memcpy_toio(dev->mem_start + lrdaaddr + 20, &rdaaddr, 4); /* advance indices */ priv->lastrxdescr = priv->nextrxdescr; if ((++priv->nextrxdescr) >= priv->rxbufcnt) priv->nextrxdescr = 0; } }
static void InitBoard(struct net_device *dev) { int camcnt; camentry_t cams[16]; u32 cammask; struct dev_mc_list *mcptr; u16 rcrval; /* reset the SONIC */ outw(CMDREG_RST, dev->base_addr + SONIC_CMDREG); udelay(10); /* clear all spurious interrupts */ outw(inw(dev->base_addr + SONIC_ISREG), dev->base_addr + SONIC_ISREG); /* set up the SONIC's bus interface - constant for this adapter - must be done while the SONIC is in reset */ outw(DCREG_USR1 | DCREG_USR0 | DCREG_WC1 | DCREG_DW32, dev->base_addr + SONIC_DCREG); outw(0, dev->base_addr + SONIC_DCREG2); /* remove reset form the SONIC */ outw(0, dev->base_addr + SONIC_CMDREG); udelay(10); /* data sheet requires URRA to be programmed before setting up the CAM contents */ outw(0, dev->base_addr + SONIC_URRA); /* program the CAM entry 0 to the device address */ camcnt = 0; putcam(cams, &camcnt, dev->dev_addr); /* start putting the multicast addresses into the CAM list. Stop if it is full. */ for (mcptr = dev->mc_list; mcptr != NULL; mcptr = mcptr->next) { putcam(cams, &camcnt, mcptr->dmi_addr); if (camcnt == 16) break; } /* calculate CAM mask */ cammask = (1 << camcnt) - 1; /* feed CDA into SONIC, initialize RCR value (always get broadcasts) */ isa_memcpy_toio(dev->mem_start, cams, sizeof(camentry_t) * camcnt); isa_memcpy_toio(dev->mem_start + (sizeof(camentry_t) * camcnt), &cammask, sizeof(cammask)); #ifdef DEBUG printk("CAM setup:\n"); dumpmem(dev, 0, sizeof(camentry_t) * camcnt + sizeof(cammask)); #endif outw(0, dev->base_addr + SONIC_CAMPTR); outw(camcnt, dev->base_addr + SONIC_CAMCNT); outw(CMDREG_LCAM, dev->base_addr + SONIC_CMDREG); if (!wait_timeout(dev, SONIC_CMDREG, CMDREG_LCAM, 0, 2)) { printk(KERN_ERR "%s:SONIC did not respond on LCAM command - giving up.", dev->name); return; } else { /* clear interrupt condition */ outw(ISREG_LCD, dev->base_addr + SONIC_ISREG); #ifdef DEBUG printk("Loading CAM done, address pointers %04x:%04x\n", inw(dev->base_addr + SONIC_URRA), inw(dev->base_addr + SONIC_CAMPTR)); { int z; printk("\n-->CAM: PTR %04x CNT %04x\n", inw(dev->base_addr + SONIC_CAMPTR), inw(dev->base_addr + SONIC_CAMCNT)); outw(CMDREG_RST, dev->base_addr + SONIC_CMDREG); for (z = 0; z < camcnt; z++) { outw(z, dev->base_addr + SONIC_CAMEPTR); printk("Entry %d: %04x %04x %04x\n", z, inw(dev->base_addr + SONIC_CAMADDR0), inw(dev->base_addr + SONIC_CAMADDR1), inw(dev->base_addr + SONIC_CAMADDR2)); } outw(0, dev->base_addr + SONIC_CMDREG); } #endif } rcrval = RCREG_BRD | RCREG_LB_NONE; /* if still multicast addresses left or ALLMULTI is set, set the multicast enable bit */ if ((dev->flags & IFF_ALLMULTI) || (mcptr != NULL)) rcrval |= RCREG_AMC; /* promiscous mode ? */ if (dev->flags & IFF_PROMISC) rcrval |= RCREG_PRO; /* program receive mode */ outw(rcrval, dev->base_addr + SONIC_RCREG); #ifdef DEBUG printk("\nRCRVAL: %04x\n", rcrval); #endif /* set up descriptors in shared memory + feed them into SONIC registers */ InitDscrs(dev); if (!InitSONIC(dev)) return; /* reset all pending interrupts */ outw(0xffff, dev->base_addr + SONIC_ISREG); /* enable transmitter + receiver interrupts */ outw(CMDREG_RXEN, dev->base_addr + SONIC_CMDREG); outw(IMREG_PRXEN | IMREG_RBEEN | IMREG_PTXEN | IMREG_TXEREN, dev->base_addr + SONIC_IMREG); /* turn on card interrupts */ outb(inb(dev->base_addr + BCMREG) | BCMREG_IEN, dev->base_addr + BCMREG); #ifdef DEBUG printk("Register dump after initialization:\n"); dumpregs(dev); #endif }
static void InitDscrs(struct net_device *dev) { ibmlana_priv *priv = (ibmlana_priv *) dev->priv; u32 addr, baddr, raddr; int z; tda_t tda; rda_t rda; rra_t rra; /* initialize RAM */ isa_memset_io(dev->mem_start, 0xaa, dev->mem_start - dev->mem_start); /* setup n TX descriptors - independent of RAM size */ priv->tdastart = addr = 0; priv->txbufstart = baddr = sizeof(tda_t) * TXBUFCNT; for (z = 0; z < TXBUFCNT; z++) { tda.status = 0; tda.config = 0; tda.length = 0; tda.fragcount = 1; tda.startlo = baddr; tda.starthi = 0; tda.fraglength = 0; if (z == TXBUFCNT - 1) tda.link = priv->tdastart; else tda.link = addr + sizeof(tda_t); tda.link |= 1; isa_memcpy_toio(dev->mem_start + addr, &tda, sizeof(tda_t)); addr += sizeof(tda_t); baddr += PKTSIZE; } /* calculate how many receive buffers fit into remaining memory */ priv->rxbufcnt = (dev->mem_end - dev->mem_start - baddr) / (sizeof(rra_t) + sizeof(rda_t) + PKTSIZE); /* calculate receive addresses */ priv->rrastart = raddr = priv->txbufstart + (TXBUFCNT * PKTSIZE); priv->rdastart = addr = priv->rrastart + (priv->rxbufcnt * sizeof(rra_t)); priv->rxbufstart = baddr = priv->rdastart + (priv->rxbufcnt * sizeof(rda_t)); for (z = 0; z < priv->rxbufcnt; z++) { rra.startlo = baddr; rra.starthi = 0; rra.cntlo = PKTSIZE >> 1; rra.cnthi = 0; isa_memcpy_toio(dev->mem_start + raddr, &rra, sizeof(rra_t)); rda.status = 0; rda.length = 0; rda.startlo = 0; rda.starthi = 0; rda.seqno = 0; if (z < priv->rxbufcnt - 1) rda.link = addr + sizeof(rda_t); else rda.link = 1; rda.inuse = 1; isa_memcpy_toio(dev->mem_start + addr, &rda, sizeof(rda_t)); baddr += PKTSIZE; raddr += sizeof(rra_t); addr += sizeof(rda_t); } /* initialize current pointers */ priv->nextrxdescr = 0; priv->lastrxdescr = priv->rxbufcnt - 1; priv->nexttxdescr = 0; priv->currtxdescr = 0; priv->txusedcnt = 0; memset(priv->txused, 0, sizeof(priv->txused)); }