📄 sk_g16.c
字号:
/*- * Function : SK_lance_init * Author : Patrick J.D. Weichmann * Date Created : 94/05/26 * * Description : Reset LANCE chip, fill RMD, TMD structures with * start values and Start LANCE. * * Parameters : I : struct net_device *dev - SK_G16 device structure * I : int mode - put LANCE into "mode" see data-sheet for * more info. * Return Value : 0 - Init done * Errors : -1 - Init failed * Update History : * YY/MM/DD uid Description-*/static int SK_lance_init(struct net_device *dev, unsigned short mode){ int i; unsigned long flags; struct priv *p = (struct priv *) dev->priv; struct tmd *tmdp; struct rmd *rmdp; PRINTK(("## %s: At beginning of LANCE init. CSR0: %#06x\n", SK_NAME, SK_read_reg(CSR0))); /* Reset LANCE */ SK_reset_board(); /* Initialize TMD's with start values */ p->tmdnum = 0; /* First descriptor for transmitting */ p->tmdlast = 0; /* First descriptor for reading stats */ for (i = 0; i < TMDNUM; i++) /* Init all TMD's */ { tmdp = p->tmdhead + i; writel((unsigned long) p->tmdbufs[i], tmdp->u.buffer); /* assign buffer */ /* Mark TMD as start and end of packet */ writeb(TX_STP | TX_ENP, &tmdp->u.s.status); } /* Initialize RMD's with start values */ p->rmdnum = 0; /* First RMD which will be used */ for (i = 0; i < RMDNUM; i++) /* Init all RMD's */ { rmdp = p->rmdhead + i; writel((unsigned long) p->rmdbufs[i], rmdp->u.buffer); /* assign buffer */ /* * LANCE must be owner at beginning so that he can fill in * receiving packets, set status and release RMD */ writeb(RX_OWN, &rmdp->u.s.status); writew(-PKT_BUF_SZ, &rmdp->blen); /* Buffer Size (two's complement) */ writeb(0, &rmdp->mlen); /* init message length */ } /* Fill LANCE Initialize Block */ writew(mode, (&((p->ram)->ib.mode))); /* Set operation mode */ for (i = 0; i < ETH_ALEN; i++) /* Set physical address */ { writeb(dev->dev_addr[i], (&((p->ram)->ib.paddr[i]))); } for (i = 0; i < 8; i++) /* Set multicast, logical address */ { writeb(0, (&((p->ram)->ib.laddr[i]))); /* We do not use logical addressing */ } /* Set ring descriptor pointers and set number of descriptors */ writel((int)p->rmdhead | RMDNUMMASK, (&((p->ram)->ib.rdrp))); writel((int)p->tmdhead | TMDNUMMASK, (&((p->ram)->ib.tdrp))); /* Prepare LANCE Control and Status Registers */ spin_lock_irqsave(&SK_lock, flags); SK_write_reg(CSR3, CSR3_ACON); /* Ale Control !!!THIS MUST BE SET!!!! */ /* * LANCE addresses the RAM from 0x0000 to 0x3fbf and has no access to * PC Memory locations. * * In structure SK_ram is defined that the first thing in ram * is the initialization block. So his address is for LANCE always * 0x0000 * * CSR1 contains low order bits 15:0 of initialization block address * CSR2 is built of: * 7:0 High order bits 23:16 of initialization block address * 15:8 reserved, must be 0 */ /* Set initialization block address (must be on word boundary) */ SK_write_reg(CSR1, 0); /* Set low order bits 15:0 */ SK_write_reg(CSR2, 0); /* Set high order bits 23:16 */ PRINTK(("## %s: After setting CSR1-3. CSR0: %#06x\n", SK_NAME, SK_read_reg(CSR0))); /* Initialize LANCE */ /* * INIT = Initialize, when set, causes the LANCE to begin the * initialization procedure and access the Init Block. */ SK_write_reg(CSR0, CSR0_INIT); spin_unlock_irqrestore(&SK_lock, flags); /* Wait until LANCE finished initialization */ SK_set_RAP(CSR0); /* Register Address Pointer to CSR0 */ for (i = 0; (i < 100) && !(SK_rread_reg() & CSR0_IDON); i++) ; /* Wait until init done or go ahead if problems (i>=100) */ if (i >= 100) /* Something is wrong ! */ { printk("%s: can't init am7990, status: %04x " "init_block: %#08x\n", dev->name, (int) SK_read_reg(CSR0), (unsigned int) &(p->ram)->ib);#ifdef SK_DEBUG SK_print_pos(dev, "LANCE INIT failed"); SK_print_dev(dev,"Device Structure:");#endif return -1; /* LANCE init failed */ } PRINTK(("## %s: init done after %d ticks\n", SK_NAME, i)); /* Clear Initialize done, enable Interrupts, start LANCE */ SK_write_reg(CSR0, CSR0_IDON | CSR0_INEA | CSR0_STRT); PRINTK(("## %s: LANCE started. CSR0: %#06x\n", SK_NAME, SK_read_reg(CSR0))); return 0; /* LANCE is up and running */} /* End of SK_lance_init() *//*- * Function : SK_send_packet * Author : Patrick J.D. Weichmann * Date Created : 94/05/27 * * Description : Writes an socket buffer into a transmit descriptor * and starts transmission. * * Parameters : I : struct sk_buff *skb - packet to transfer * I : struct net_device *dev - SK_G16 device structure * Return Value : 0 - OK * 1 - Could not transmit (dev_queue_xmit will queue it) * and try to sent it later * Globals : None * Side Effects : None * Update History : * YY/MM/DD uid Description-*/static void SK_timeout(struct net_device *dev){ printk(KERN_WARNING "%s: xmitter timed out, try to restart!\n", dev->name); SK_lance_init(dev, MODE_NORMAL); /* Reinit LANCE */ netif_wake_queue(dev); /* Clear Transmitter flag */ dev->trans_start = jiffies; /* Mark Start of transmission */}static int SK_send_packet(struct sk_buff *skb, struct net_device *dev){ struct priv *p = (struct priv *) dev->priv; struct tmd *tmdp; PRINTK2(("## %s: SK_send_packet() called, CSR0 %#04x.\n", SK_NAME, SK_read_reg(CSR0))); /* * Block a timer-based transmit from overlapping. * This means check if we are already in. */ netif_stop_queue (dev); { /* Evaluate Packet length */ short len = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN; tmdp = p->tmdhead + p->tmdnum; /* Which descriptor for transmitting */ /* Fill in Transmit Message Descriptor */ /* Copy data into dual ported ram */ memcpy_toio((tmdp->u.buffer & 0x00ffffff), skb->data, skb->len); writew(-len, &tmdp->blen); /* set length to transmit */ /* * Packet start and end is always set because we use the maximum * packet length as buffer length. * Relinquish ownership to LANCE */ writeb(TX_OWN | TX_STP | TX_ENP, &tmdp->u.s.status); /* Start Demand Transmission */ SK_write_reg(CSR0, CSR0_TDMD | CSR0_INEA); dev->trans_start = jiffies; /* Mark start of transmission */ /* Set pointer to next transmit buffer */ p->tmdnum++; p->tmdnum &= TMDNUM-1; /* Do we own the next transmit buffer ? */ if (! (readb(&((p->tmdhead + p->tmdnum)->u.s.status)) & TX_OWN) ) { /* * We own next buffer and are ready to transmit, so * clear busy flag */ netif_start_queue(dev); } p->stats.tx_bytes += skb->len; } dev_kfree_skb(skb); return 0; } /* End of SK_send_packet *//*- * Function : SK_interrupt * Author : Patrick J.D. Weichmann * Date Created : 94/05/27 * * Description : SK_G16 interrupt handler which checks for LANCE * Errors, handles transmit and receive interrupts * * Parameters : I : int irq, void *dev_id, struct pt_regs * regs - * Return Value : None * Errors : None * Globals : None * Side Effects : None * Update History : * YY/MM/DD uid Description-*/static void SK_interrupt(int irq, void *dev_id, struct pt_regs * regs){ int csr0; struct net_device *dev = dev_id; struct priv *p = (struct priv *) dev->priv; PRINTK2(("## %s: SK_interrupt(). status: %#06x\n", SK_NAME, SK_read_reg(CSR0))); if (dev == NULL) { printk("SK_interrupt(): IRQ %d for unknown device.\n", irq); } spin_lock (&SK_lock); csr0 = SK_read_reg(CSR0); /* store register for checking */ /* * Acknowledge all of the current interrupt sources, disable * Interrupts (INEA = 0) */ SK_write_reg(CSR0, csr0 & CSR0_CLRALL); if (csr0 & CSR0_ERR) /* LANCE Error */ { printk("%s: error: %04x\n", dev->name, csr0); if (csr0 & CSR0_MISS) /* No place to store packet ? */ { p->stats.rx_dropped++; } } if (csr0 & CSR0_RINT) /* Receive Interrupt (packet arrived) */ { SK_rxintr(dev); } if (csr0 & CSR0_TINT) /* Transmit interrupt (packet sent) */ { SK_txintr(dev); } SK_write_reg(CSR0, CSR0_INEA); /* Enable Interrupts */ spin_unlock (&SK_lock);} /* End of SK_interrupt() */ /*- * Function : SK_txintr * Author : Patrick J.D. Weichmann * Date Created : 94/05/27 * * Description : After sending a packet we check status, update * statistics and relinquish ownership of transmit * descriptor ring. * * Parameters : I : struct net_device *dev - SK_G16 device structure * Return Value : None * Errors : None * Globals : None * Update History : * YY/MM/DD uid Description-*/static void SK_txintr(struct net_device *dev){ int tmdstat; struct tmd *tmdp; struct priv *p = (struct priv *) dev->priv; PRINTK2(("## %s: SK_txintr() status: %#06x\n", SK_NAME, SK_read_reg(CSR0))); tmdp = p->tmdhead + p->tmdlast; /* Which buffer we sent at last ? */ /* Set next buffer */ p->tmdlast++; p->tmdlast &= TMDNUM-1; tmdstat = readb(&tmdp->u.s.status); /* * We check status of transmitted packet. * see LANCE data-sheet for error explanation */ if (tmdstat & TX_ERR) /* Error occurred */ { int stat2 = readw(&tmdp->status2); printk("%s: TX error: %04x %04x\n", dev->name, tmdstat, stat2); if (stat2 & TX_TDR) /* TDR problems? */ { printk("%s: tdr-problems \n", dev->name); } if (stat2 & TX_RTRY) /* Failed in 16 attempts to transmit ? */ p->stats.tx_aborted_errors++; if (stat2 & TX_LCOL) /* Late collision ? */ p->stats.tx_window_errors++; if (stat2 & TX_LCAR) /* Loss of Carrier ? */ p->stats.tx_carrier_errors++; if (stat2 & TX_UFLO) /* Underflow error ? */ { p->stats.tx_fifo_errors++; /* * If UFLO error occurs it will turn transmitter of. * So we must reinit LANCE */ SK_lance_init(dev, MODE_NORMAL); } p->stats.tx_errors++; writew(0, &tmdp->status2); /* Clear error flags */ } else if (tmdstat & TX_MORE) /* Collisions occurred ? */ { /* * Here I have a problem. * I only know that there must be one or up to 15 collisions. * That's why TX_MORE is set, because after 16 attempts TX_RTRY * will be set which means couldn't send packet aborted transfer. * * First I did not have this in but then I thought at minimum * we see that something was not ok. * If anyone knows something better than this to handle this * please report it. */ p->stats.collisions++; } else /* Packet sent without any problems */ { p->stats.tx_packets++; } /* * We mark transmitter not busy anymore, because now we have a free * transmit descriptor which can be filled by SK_send_packet and * afterwards sent by the LANCE * * The function which do handle slow IRQ parts is do_bottom_half() * which runs at normal kernel priority, that means all interrupt are * enabled. (see kernel/irq.c) * * net_bh does something like this: * - check if already in net_bh * - try to transmit something from the send queue * - if something is in the receive queue send it up to higher * levels if it is a known protocol * - try to transmit something from the send queue */ netif_wake_queue(dev);} /* End of SK_txintr() *//*- * Function : SK_rxintr * Author : Patrick J.D. Weichmann * Date Created : 94/05/27 * * Description : Buffer sent, check for errors, relinquish ownership * of the receive message descriptor. * * Parameters : I : SK_G16 device structure * Return Value : None * Globals : None * Update History : * YY/MM/DD uid Description-*/static void SK_rxintr(struct net_device *dev){ struct rmd *rmdp; int rmdstat; struct priv *p = (struct priv *) dev->priv; PRINTK2(("## %s: SK_rxintr(). CSR0: %#06x\n", SK_NAME, SK_read_reg(CSR0))); rmdp = p->rmdhead + p->rmdnum; /* As long as we own the next entry, check status and send * it up to higher layer */ while (!( (rmdstat = readb(&rmdp->u.s.status)) & RX_OWN)) { /* * Start and end of packet must be set, because we use * the ethernet maximum packet length (1518) as buffer size. * * Because our buffers are at maximum OFLO and BUFF errors are * not to be concerned (see Data sheet) */ if ((rmdstat & (RX_STP | RX_ENP)) != (RX_STP | RX_ENP)) { /* Start of a frame > 1518 Bytes ? */ if (rmdstat & RX_STP) { p->stats.rx_errors++; /* bad packet received */ p->stats.rx_length_errors++; /* packet too long */ printk("%s: packet too long\n", dev->name); } /* * All other packets will be ignored until a new frame with * start (RX_STP) set follows. * * What we do is just give descriptor free for new incoming * packets. */ writeb(RX_OWN, &rmdp->u.s.status); /* Relinquish ownership to LANCE */ } else if (rmdstat & RX_ERR) /* Receive Error ? */ { printk("%s: RX error: %04x\n", dev->name, (int) rmdstat); p->stats.rx_errors++; if (rmdstat & RX_FRAM) p->stats.rx_frame_errors++; if (rmdstat & RX_CRC) p->stats.rx_crc_errors++; writeb(RX_OWN, &rmdp->u.s.status); /* Relinquish ownership to LANCE */ } else /* We have a packet which can be queued for the upper layers */ { int len = readw(&rmdp->mlen) & 0x0fff; /* extract message length from receive buffer */ struct sk_buff *skb; skb = dev_alloc_skb(len+2); /* allocate socket buffer */ if (skb == NULL) /* Could not get mem ? */ { /*
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -