📄 enet.c
字号:
* These get messed up if we get called due to a busy condition. */ bdp = cep->cur_rx; for (;;) { if (bdp->status & BD_ENET_RX_EMPTY) break; #ifndef final_version /* Since we have allocated space to hold a complete frame, both * the first and last indicators should be set. */ if ((bdp->status & (BD_ENET_RX_FIRST | BD_ENET_RX_LAST)) != (BD_ENET_RX_FIRST | BD_ENET_RX_LAST)) printk("CPM ENET: rcv is not first+last\n");#endif /* Frame too long or too short. */ if (bdp->status & (BD_ENET_RX_LG | BD_ENET_RX_SH)) cep->stats.rx_length_errors++; if (bdp->status & BD_ENET_RX_NO) /* Frame alignment */ cep->stats.rx_frame_errors++; if (bdp->status & BD_ENET_RX_CR) /* CRC Error */ cep->stats.rx_crc_errors++; if (bdp->status & BD_ENET_RX_OV) /* FIFO overrun */ cep->stats.rx_crc_errors++; /* Report late collisions as a frame error. * On this error, the BD is closed, but we don't know what we * have in the buffer. So, just drop this frame on the floor. */ if (bdp->status & BD_ENET_RX_CL) { cep->stats.rx_frame_errors++; } else { /* Process the incoming frame. */ cep->stats.rx_packets++; pkt_len = bdp->length; /* cep->stats.rx_bytes += pkt_len; */ /* TODO: It would really be nice... */ /* This does 16 byte alignment, much more than we need. * The packet length includes FCS, but we don't want to * include that when passing upstream as it messes up * bridging applications. */ skb = dev_alloc_skb(pkt_len-4); if (skb == NULL) { printk("%s: Memory squeeze, dropping packet.\n", dev->name); cep->stats.rx_dropped++; } else { skb->dev = dev; skb_put(skb,pkt_len-4); /* Make room */ eth_copy_and_sum(skb, (unsigned char *)bdp->buf, pkt_len-4, 0); skb->protocol=eth_type_trans(skb,dev); netif_rx(skb); } } /* Clear the status flags for this buffer. */ bdp->status &= ~BD_ENET_RX_STATS; /* Mark the buffer empty. */ bdp->status |= BD_ENET_RX_EMPTY; /* Update BD pointer to next entry. */ if (bdp->status & BD_ENET_RX_WRAP) bdp = cep->rx_bd_base; else bdp++; } cep->cur_rx = (QUICC_BD *)bdp; return 0;}static intscc_enet_close(struct net_device *dev){ /* Don't know what to do yet. */ /* netif_stop_queue(dev); */ return 0;}/* static struct net_device_stats *scc_enet_get_stats(struct net_device *dev) */static struct enet_statistics *scc_enet_get_stats(struct net_device *dev){ struct scc_enet_private *cep = (struct scc_enet_private *)dev->priv; return &cep->stats;}/* Set or clear the multicast filter for this adaptor. * Skeleton taken from sunlance driver. * The CPM Ethernet implementation allows Multicast as well as individual * MAC address filtering. Some of the drivers check to make sure it is * a group multicast address, and discard those that are not. I guess I * will do the same for now, but just remove the test if you want * individual filtering as well (do the upper net layers want or support * this kind of feature?). */static void set_multicast_list(struct net_device *dev){ struct scc_enet_private *cep; struct dev_mc_list *dmi; u_char *mcptr, *tdptr; volatile scc_enet_t *ep; int i, j; volatile QUICC *cp = pquicc; cep = (struct scc_enet_private *)dev->priv; /* Get pointer to SCC area in parameter RAM. */ ep = (scc_enet_t *)dev->base_addr; if (dev->flags&IFF_PROMISC) { /* Log any net taps. */ printk("%s: Promiscuous mode enabled.\n", dev->name); cep->sccp->scc_psmr |= ETHER_PRO; } else { cep->sccp->scc_psmr &= ~ETHER_PRO; if (dev->flags & IFF_ALLMULTI) { /* Catch all multicast addresses, so set the * filter to all 1's. */ ep->sen_gaddr1 = 0xffff; ep->sen_gaddr2 = 0xffff; ep->sen_gaddr3 = 0xffff; ep->sen_gaddr4 = 0xffff; } else { /* Clear filter and add the addresses in the list. */ ep->sen_gaddr1 = 0; ep->sen_gaddr2 = 0; ep->sen_gaddr3 = 0; ep->sen_gaddr4 = 0; dmi = dev->mc_list; for (i=0; i<dev->mc_count; i++) { /* Only support group multicast for now. */ if (!(dmi->dmi_addr[0] & 1)) continue; /* The address in dmi_addr is LSB first, * and taddr is MSB first. We have to * copy bytes MSB first from dmi_addr. */ mcptr = (u_char *)dmi->dmi_addr + 5; tdptr = (u_char *)&ep->sen_taddrh; for (j=0; j<6; j++) *tdptr++ = *mcptr--; /* Ask CPM to run CRC and set bit in * filter mask. */ cp->cp_cr = mk_cr_cmd(CPM_CR_ENET, CPM_CR_SET_GADDR) | CPM_CR_FLG; /* this delay is necessary here -- Cort */ udelay(10); while (cp->cp_cr & CPM_CR_FLG); } } }}/* Initialize the CPM Ethernet on SCC. */int scc_enet_init(void){ struct net_device *dev; struct scc_enet_private *cep; int i, j; unsigned char *eap; /* unsigned long mem_addr; */ /* pte_t *pte; */ /* bd_t *bd; */ /* `board tag' used by ppc - TODO: integrate uC bootloader vars */ volatile QUICC_BD *bdp; volatile QUICC *cp; volatile struct scc_regs *sccp; volatile struct ethernet_pram *ep; /* volatile immap_t *immap; */ cp = pquicc; /* Get pointer to Communication Processor */ /* immap = (immap_t *)IMAP_ADDR; */ /* and to internal registers */ /* bd = (bd_t *)__res; */ /* Allocate some private information. */ cep = (struct scc_enet_private *)kmalloc(sizeof(*cep), GFP_KERNEL); memset(cep, 0, sizeof(*cep)); /* __clear_user(cep,sizeof(*cep)); */ /* spin_lock_init(&cep->lock); */ /* TODO: SPINLOCK */ /* Create an Ethernet device instance. */ dev = init_etherdev(0, 0); /* Get pointer to SCC area in parameter RAM. */ /* ep = (ethernet_pram *)(&cp->cp_dparam[PROFF_ENET]); */ ep = &pquicc->pram[SCC_ENET].enet_scc; /* And another to the SCC register area. */ sccp = &pquicc->scc_regs[SCC_ENET]; cep->sccp = sccp; /* Keep the pointer handy */ /* Disable receive and transmit in case EPPC-Bug started it. */ sccp->scc_gsmr.w.low &= ~(SCC_GSMRL_ENR | SCC_GSMRL_ENT); /* Set up 360 pins for SCC interface to ethernet transceiver. * Pin mappings (PA_xx and PC_xx) are defined in commproc.h */ /* Configure port A pins for Txd and Rxd. */ pquicc->pio_papar |= (PA_ENET_RXD | PA_ENET_TXD); pquicc->pio_padir &= ~(PA_ENET_RXD | PA_ENET_TXD); pquicc->pio_paodr &= ~PA_ENET_TXD; /* Configure port C pins to enable CLSN and RENA. */ pquicc->pio_pcpar &= ~(PC_ENET_CLSN | PC_ENET_RENA); pquicc->pio_pcdir &= ~(PC_ENET_CLSN | PC_ENET_RENA); pquicc->pio_pcso |= (PC_ENET_CLSN | PC_ENET_RENA); /* Configure port A for TCLK and RCLK. */ pquicc->pio_papar |= (PA_ENET_TCLK | PA_ENET_RCLK); pquicc->pio_padir &= ~(PA_ENET_TCLK | PA_ENET_RCLK); /* Configure Serial Interface clock routing. * First, clear all SCC bits to zero, then set the ones we want. */ pquicc->si_sicr &= ~SICR_ENET_MASK; pquicc->si_sicr |= SICR_ENET_CLKRT; /* Allocate space for the buffer descriptors in the DP ram. * These are relative offsets in the DP ram address space. * Initialize base addresses for the buffer descriptors. */ i = m360_cpm_dpalloc(sizeof(QUICC_BD) * RX_RING_SIZE); ep->rbase = i; cep->rx_bd_base = (QUICC_BD *)((uint)pquicc + i); i = m360_cpm_dpalloc(sizeof(QUICC_BD) * TX_RING_SIZE); ep->tbase = i; cep->tx_bd_base = (QUICC_BD *)((uint)pquicc + i); cep->dirty_tx = cep->cur_tx = cep->tx_bd_base; cep->cur_rx = cep->rx_bd_base; /* Issue init Rx BD command for SCC. * Manual says to perform an Init Rx parameters here. We have * to perform both Rx and Tx because the SCC may have been * already running. [In uCquicc's case, I don't think that is so - mles] * In addition, we have to do it later because we don't yet have * all of the BD control/status set properly. cp->cp_cpcr = mk_cr_cmd(CPM_CR_ENET, CPM_CR_INIT_RX) | CPM_CR_FLG; while (cp->cp_cpcr & CPM_CR_FLG); */ /* Initialize function code registers for big-endian. */ ep->rfcr = (SCC_EB | SCC_FC_DMA); ep->tfcr = (SCC_EB | SCC_FC_DMA); /* Set maximum bytes per receive buffer. * This appears to be an Ethernet frame size, not the buffer * fragment size. It must be a multiple of four. */ ep->mrblr = PKT_MAXBLR_SIZE; /* Set CRC preset and mask. */ ep->c_pres = 0xffffffff; ep->c_mask = 0xdebb20e3; /* see 360UM p. 7-247 */ ep->crcec = 0; /* CRC Error counter */ ep->alec = 0; /* alignment error counter */ ep->disfc = 0; /* discard frame counter */ ep->pads = 0x8888; /* Tx short frame pad character */ ep->ret_lim = 0x000f; /* Retry limit threshold */ ep->mflr = PKT_MAXBUF_SIZE; /* maximum frame length register */ ep->minflr = PKT_MINBUF_SIZE; /* minimum frame length register */ ep->maxd1 = PKT_MAXBLR_SIZE; /* maximum DMA1 length */ ep->maxd2 = PKT_MAXBLR_SIZE; /* maximum DMA2 length */ /* Clear hash tables, group and individual. */ ep->gaddr1 = ep->gaddr2 = ep->gaddr3 = ep->gaddr4 = 0; ep->iaddr1 = ep->iaddr2 = ep->iaddr3 = ep->iaddr4 = 0; /* Set Ethernet station address. * * The uCbootloader provides a hook to the kernel to retrieve * stuff like the MAC address. This is retrieved in config_BSP() */#if defined (CONFIG_UCQUICC) { extern unsigned char *scc1_hwaddr; eap = (char *)ep->paddr.b; for (i=5; i>=0; i--) *eap++ = dev->dev_addr[i] = scc1_hwaddr[i]; }#endif/* #ifndef CONFIG_MBX *//* eap = (unsigned char *)&(ep->paddrh); *//* for (i=5; i>=0; i--) *//* *eap++ = dev->dev_addr[i] = bd->bi_enetaddr[i]; *//* #else *//* for (i=5; i>=0; i--) *//* dev->dev_addr[i] = *eap++; *//* #endif */ ep->p_per = 0; /* 'cause the book says so */ ep->taddr_l = 0; /* temp address (LSB) */ ep->taddr_m = 0; ep->taddr_h = 0; /* temp address (MSB) */ /* Now allocate the host memory pages and initialize the * buffer descriptors. */ /* initialize rx buffer descriptors */ bdp = cep->tx_bd_base; for (j=0; j<(TX_RING_SIZE-1); j++) { bdp->buf = 0; bdp->status = 0; bdp++; } bdp->buf = 0; bdp->status = BD_SC_WRAP; /* initialize rx buffer descriptors */ bdp = cep->rx_bd_base; for (j=0; j<(RX_RING_SIZE-1); j++) { bdp->buf = &rx_buf_pool[j * CPM_ENET_RX_FRSIZE]; bdp->status = BD_SC_EMPTY | BD_SC_INTRPT; bdp++; } bdp->buf = &rx_buf_pool[j * CPM_ENET_RX_FRSIZE]; bdp->status = BD_SC_WRAP | BD_SC_EMPTY | BD_SC_INTRPT; /* Let's re-initialize the channel now. We have to do it later * than the manual describes because we have just now finished * the BD initialization. */ cp->cp_cr = mk_cr_cmd(CPM_CR_ENET, CPM_CR_INIT_TRX) | CPM_CR_FLG; while (cp->cp_cr & CPM_CR_FLG); cep->skb_cur = cep->skb_dirty = 0; sccp->scc_scce = 0xffff; /* Clear any pending events */ /* Enable interrupts for transmit error, complete frame * received, and any transmit buffer we have also set the * interrupt flag. */ sccp->scc_sccm = (SCCE_ENET_TXE | SCCE_ENET_RXF | SCCE_ENET_TXB); /* Install our interrupt handler. */ /* cpm_install_handler(CPMVEC_ENET, scc_enet_interrupt, dev); */ request_irq(IRQ_MACHSPEC | CPMVEC_ENET, scc_enet_interrupt, IRQ_FLG_LOCK, dev->name, (void *)dev); /* Set GSMR_H to enable all normal operating modes. * Set GSMR_L to enable Ethernet to MC68160. */ sccp->scc_gsmr.w.high = 0; sccp->scc_gsmr.w.low = (SCC_GSMRL_TCI | SCC_GSMRL_TPL_48 | SCC_GSMRL_TPP_10 | SCC_GSMRL_MODE_ENET); /* Set sync/delimiters. */ sccp->scc_dsr = 0xd555; /* Set processing mode. Use Ethernet CRC, catch broadcast, and * start frame search 22 bit times after RENA. */ sccp->scc_psmr = (SCC_PMSR_ENCRC /* Ethernet CRC mode */ /* | SCC_PSMR_HBC */ /* Enable heartbeat */ /* | SCC_PMSR_PRO */ /* Promiscuous mode */ /* | SCC_PMSR_FDE */ /* Full duplex enable */ | ETHER_NIB_22); /* sccp->scc_psmr = (SCC_PMSR_PRO | ETHER_CRC_32 | ETHER_NIB_22); */ /* It is now OK to enable the Ethernet transmitter. * Unfortunately, there are board implementation differences here. */#if defined(CONFIG_UCQUICC)/* immap->im_ioport.iop_pcpar |= PC_ENET_TENA; *//* immap->im_ioport.iop_pcdir &= ~PC_ENET_TENA; */ cp->pio_pcpar |= PC_ENET_TENA; /* t_en */ cp->pio_pcdir &= ~PC_ENET_TENA; cp->pip_pbpar &= ~(0x00000200); /* power up ethernet transceiver */ cp->pip_pbdir |= (0x00000200); cp->pip_pbdat |= (0x00000200);#endif dev->base_addr = (unsigned long)ep; dev->priv = cep;#if 0 dev->name = "CPM_ENET";#endif /* The CPM Ethernet specific entries in the device structure. */ dev->open = scc_enet_open; dev->hard_start_xmit = scc_enet_start_xmit; /* dev->tx_timeout = scc_enet_timeout; */ /* dev->watchdog_timeo = TX_TIMEOUT; */ dev->stop = scc_enet_close; dev->get_stats = scc_enet_get_stats; dev->set_multicast_list = set_multicast_list; /* And last, enable the transmit and receive processing. */ sccp->scc_gsmr.w.low |= (SCC_GSMRL_ENR | SCC_GSMRL_ENT); printk("%s: CPM ENET Version 0.3, ", dev->name); for (i=0; i<5; i++) printk("%02x:", dev->dev_addr[i]); printk("%02x\n", dev->dev_addr[5]); return 0;}int m68360_enet_probe(struct device *dev){ scc_enet_init (); }/* * Local variables: * c-indent-level: 4 * c-basic-offset: 4 * tab-width: 4 * End: */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -