sb1250-mac.c
来自「linux 内核源代码」· C语言 代码 · 共 2,649 行 · 第 1/5 页
C
2,649 行
return 0xffff;}/********************************************************************** * SBMAC_MII_WRITE(bus, phyaddr, regidx, regval) * * Write a value to a PHY register. * * Input parameters: * bus - MDIO bus handle * phyaddr - PHY to use * regidx - register within the PHY * regval - data to write to register * * Return value: * 0 for success ********************************************************************* */static int sbmac_mii_write(struct mii_bus *bus, int phyaddr, int regidx, u16 regval){ struct sbmac_softc *sc = (struct sbmac_softc *)bus->priv; void __iomem *sbm_mdio = sc->sbm_mdio; int mac_mdio_genc; sbmac_mii_sync(sbm_mdio); sbmac_mii_senddata(sbm_mdio, MII_COMMAND_START, 2); sbmac_mii_senddata(sbm_mdio, MII_COMMAND_WRITE, 2); sbmac_mii_senddata(sbm_mdio, phyaddr, 5); sbmac_mii_senddata(sbm_mdio, regidx, 5); sbmac_mii_senddata(sbm_mdio, MII_COMMAND_ACK, 2); sbmac_mii_senddata(sbm_mdio, regval, 16); mac_mdio_genc = __raw_readq(sbm_mdio) & M_MAC_GENC; __raw_writeq(M_MAC_MDIO_DIR_OUTPUT | mac_mdio_genc, sbm_mdio); return 0;}/********************************************************************** * SBDMA_INITCTX(d,s,chan,txrx,maxdescr) * * Initialize a DMA channel context. Since there are potentially * eight DMA channels per MAC, it's nice to do this in a standard * way. * * Input parameters: * d - struct sbmacdma (DMA channel context) * s - struct sbmac_softc (pointer to a MAC) * chan - channel number (0..1 right now) * txrx - Identifies DMA_TX or DMA_RX for channel direction * maxdescr - number of descriptors * * Return value: * nothing ********************************************************************* */static void sbdma_initctx(struct sbmacdma *d, struct sbmac_softc *s, int chan, int txrx, int maxdescr){#ifdef CONFIG_SBMAC_COALESCE int int_pktcnt, int_timeout;#endif /* * Save away interesting stuff in the structure */ d->sbdma_eth = s; d->sbdma_channel = chan; d->sbdma_txdir = txrx;#if 0 /* RMON clearing */ s->sbe_idx =(s->sbm_base - A_MAC_BASE_0)/MAC_SPACING;#endif __raw_writeq(0, s->sbm_base + R_MAC_RMON_TX_BYTES); __raw_writeq(0, s->sbm_base + R_MAC_RMON_COLLISIONS); __raw_writeq(0, s->sbm_base + R_MAC_RMON_LATE_COL); __raw_writeq(0, s->sbm_base + R_MAC_RMON_EX_COL); __raw_writeq(0, s->sbm_base + R_MAC_RMON_FCS_ERROR); __raw_writeq(0, s->sbm_base + R_MAC_RMON_TX_ABORT); __raw_writeq(0, s->sbm_base + R_MAC_RMON_TX_BAD); __raw_writeq(0, s->sbm_base + R_MAC_RMON_TX_GOOD); __raw_writeq(0, s->sbm_base + R_MAC_RMON_TX_RUNT); __raw_writeq(0, s->sbm_base + R_MAC_RMON_TX_OVERSIZE); __raw_writeq(0, s->sbm_base + R_MAC_RMON_RX_BYTES); __raw_writeq(0, s->sbm_base + R_MAC_RMON_RX_MCAST); __raw_writeq(0, s->sbm_base + R_MAC_RMON_RX_BCAST); __raw_writeq(0, s->sbm_base + R_MAC_RMON_RX_BAD); __raw_writeq(0, s->sbm_base + R_MAC_RMON_RX_GOOD); __raw_writeq(0, s->sbm_base + R_MAC_RMON_RX_RUNT); __raw_writeq(0, s->sbm_base + R_MAC_RMON_RX_OVERSIZE); __raw_writeq(0, s->sbm_base + R_MAC_RMON_RX_FCS_ERROR); __raw_writeq(0, s->sbm_base + R_MAC_RMON_RX_LENGTH_ERROR); __raw_writeq(0, s->sbm_base + R_MAC_RMON_RX_CODE_ERROR); __raw_writeq(0, s->sbm_base + R_MAC_RMON_RX_ALIGN_ERROR); /* * initialize register pointers */ d->sbdma_config0 = s->sbm_base + R_MAC_DMA_REGISTER(txrx,chan,R_MAC_DMA_CONFIG0); d->sbdma_config1 = s->sbm_base + R_MAC_DMA_REGISTER(txrx,chan,R_MAC_DMA_CONFIG1); d->sbdma_dscrbase = s->sbm_base + R_MAC_DMA_REGISTER(txrx,chan,R_MAC_DMA_DSCR_BASE); d->sbdma_dscrcnt = s->sbm_base + R_MAC_DMA_REGISTER(txrx,chan,R_MAC_DMA_DSCR_CNT); d->sbdma_curdscr = s->sbm_base + R_MAC_DMA_REGISTER(txrx,chan,R_MAC_DMA_CUR_DSCRADDR); if (d->sbdma_txdir) d->sbdma_oodpktlost = NULL; else d->sbdma_oodpktlost = s->sbm_base + R_MAC_DMA_REGISTER(txrx,chan,R_MAC_DMA_OODPKTLOST_RX); /* * Allocate memory for the ring */ d->sbdma_maxdescr = maxdescr; d->sbdma_dscrtable_unaligned = kcalloc(d->sbdma_maxdescr + 1, sizeof(*d->sbdma_dscrtable), GFP_KERNEL); /* * The descriptor table must be aligned to at least 16 bytes or the * MAC will corrupt it. */ d->sbdma_dscrtable = (struct sbdmadscr *) ALIGN((unsigned long)d->sbdma_dscrtable_unaligned, sizeof(*d->sbdma_dscrtable)); d->sbdma_dscrtable_end = d->sbdma_dscrtable + d->sbdma_maxdescr; d->sbdma_dscrtable_phys = virt_to_phys(d->sbdma_dscrtable); /* * And context table */ d->sbdma_ctxtable = kcalloc(d->sbdma_maxdescr, sizeof(*d->sbdma_ctxtable), GFP_KERNEL);#ifdef CONFIG_SBMAC_COALESCE /* * Setup Rx/Tx DMA coalescing defaults */ int_pktcnt = (txrx == DMA_TX) ? int_pktcnt_tx : int_pktcnt_rx; if ( int_pktcnt ) { d->sbdma_int_pktcnt = int_pktcnt; } else { d->sbdma_int_pktcnt = 1; } int_timeout = (txrx == DMA_TX) ? int_timeout_tx : int_timeout_rx; if ( int_timeout ) { d->sbdma_int_timeout = int_timeout; } else { d->sbdma_int_timeout = 0; }#endif}/********************************************************************** * SBDMA_CHANNEL_START(d) * * Initialize the hardware registers for a DMA channel. * * Input parameters: * d - DMA channel to init (context must be previously init'd * rxtx - DMA_RX or DMA_TX depending on what type of channel * * Return value: * nothing ********************************************************************* */static void sbdma_channel_start(struct sbmacdma *d, int rxtx){ /* * Turn on the DMA channel */#ifdef CONFIG_SBMAC_COALESCE __raw_writeq(V_DMA_INT_TIMEOUT(d->sbdma_int_timeout) | 0, d->sbdma_config1); __raw_writeq(M_DMA_EOP_INT_EN | V_DMA_RINGSZ(d->sbdma_maxdescr) | V_DMA_INT_PKTCNT(d->sbdma_int_pktcnt) | 0, d->sbdma_config0);#else __raw_writeq(0, d->sbdma_config1); __raw_writeq(V_DMA_RINGSZ(d->sbdma_maxdescr) | 0, d->sbdma_config0);#endif __raw_writeq(d->sbdma_dscrtable_phys, d->sbdma_dscrbase); /* * Initialize ring pointers */ d->sbdma_addptr = d->sbdma_dscrtable; d->sbdma_remptr = d->sbdma_dscrtable;}/********************************************************************** * SBDMA_CHANNEL_STOP(d) * * Initialize the hardware registers for a DMA channel. * * Input parameters: * d - DMA channel to init (context must be previously init'd * * Return value: * nothing ********************************************************************* */static void sbdma_channel_stop(struct sbmacdma *d){ /* * Turn off the DMA channel */ __raw_writeq(0, d->sbdma_config1); __raw_writeq(0, d->sbdma_dscrbase); __raw_writeq(0, d->sbdma_config0); /* * Zero ring pointers */ d->sbdma_addptr = NULL; d->sbdma_remptr = NULL;}static void sbdma_align_skb(struct sk_buff *skb,int power2,int offset){ unsigned long addr; unsigned long newaddr; addr = (unsigned long) skb->data; newaddr = (addr + power2 - 1) & ~(power2 - 1); skb_reserve(skb,newaddr-addr+offset);}/********************************************************************** * SBDMA_ADD_RCVBUFFER(d,sb) * * Add a buffer to the specified DMA channel. For receive channels, * this queues a buffer for inbound packets. * * Input parameters: * d - DMA channel descriptor * sb - sk_buff to add, or NULL if we should allocate one * * Return value: * 0 if buffer could not be added (ring is full) * 1 if buffer added successfully ********************************************************************* */static int sbdma_add_rcvbuffer(struct sbmacdma *d, struct sk_buff *sb){ struct sbdmadscr *dsc; struct sbdmadscr *nextdsc; struct sk_buff *sb_new = NULL; int pktsize = ENET_PACKET_SIZE; /* get pointer to our current place in the ring */ dsc = d->sbdma_addptr; nextdsc = SBDMA_NEXTBUF(d,sbdma_addptr); /* * figure out if the ring is full - if the next descriptor * is the same as the one that we're going to remove from * the ring, the ring is full */ if (nextdsc == d->sbdma_remptr) { return -ENOSPC; } /* * Allocate a sk_buff if we don't already have one. * If we do have an sk_buff, reset it so that it's empty. * * Note: sk_buffs don't seem to be guaranteed to have any sort * of alignment when they are allocated. Therefore, allocate enough * extra space to make sure that: * * 1. the data does not start in the middle of a cache line. * 2. The data does not end in the middle of a cache line * 3. The buffer can be aligned such that the IP addresses are * naturally aligned. * * Remember, the SOCs MAC writes whole cache lines at a time, * without reading the old contents first. So, if the sk_buff's * data portion starts in the middle of a cache line, the SOC * DMA will trash the beginning (and ending) portions. */ if (sb == NULL) { sb_new = dev_alloc_skb(ENET_PACKET_SIZE + SMP_CACHE_BYTES * 2 + ETHER_ALIGN); if (sb_new == NULL) { pr_info("%s: sk_buff allocation failed\n", d->sbdma_eth->sbm_dev->name); return -ENOBUFS; } sbdma_align_skb(sb_new, SMP_CACHE_BYTES, ETHER_ALIGN); } else { sb_new = sb; /* * nothing special to reinit buffer, it's already aligned * and sb->data already points to a good place. */ } /* * fill in the descriptor */#ifdef CONFIG_SBMAC_COALESCE /* * Do not interrupt per DMA transfer. */ dsc->dscr_a = virt_to_phys(sb_new->data) | V_DMA_DSCRA_A_SIZE(NUMCACHEBLKS(pktsize+ETHER_ALIGN)) | 0;#else dsc->dscr_a = virt_to_phys(sb_new->data) | V_DMA_DSCRA_A_SIZE(NUMCACHEBLKS(pktsize+ETHER_ALIGN)) | M_DMA_DSCRA_INTERRUPT;#endif /* receiving: no options */ dsc->dscr_b = 0; /* * fill in the context */ d->sbdma_ctxtable[dsc-d->sbdma_dscrtable] = sb_new; /* * point at next packet */ d->sbdma_addptr = nextdsc; /* * Give the buffer to the DMA engine. */ __raw_writeq(1, d->sbdma_dscrcnt); return 0; /* we did it */}/********************************************************************** * SBDMA_ADD_TXBUFFER(d,sb) * * Add a transmit buffer to the specified DMA channel, causing a * transmit to start. * * Input parameters: * d - DMA channel descriptor * sb - sk_buff to add * * Return value: * 0 transmit queued successfully * otherwise error code ********************************************************************* */static int sbdma_add_txbuffer(struct sbmacdma *d, struct sk_buff *sb){ struct sbdmadscr *dsc; struct sbdmadscr *nextdsc; uint64_t phys; uint64_t ncb; int length; /* get pointer to our current place in the ring */ dsc = d->sbdma_addptr; nextdsc = SBDMA_NEXTBUF(d,sbdma_addptr); /* * figure out if the ring is full - if the next descriptor * is the same as the one that we're going to remove from * the ring, the ring is full */ if (nextdsc == d->sbdma_remptr) { return -ENOSPC; } /* * Under Linux, it's not necessary to copy/coalesce buffers * like it is on NetBSD. We think they're all contiguous, * but that may not be true for GBE. */ length = sb->len; /* * fill in the descriptor. Note that the number of cache * blocks in the descriptor is the number of blocks * *spanned*, so we need to add in the offset (if any) * while doing the calculation. */ phys = virt_to_phys(sb->data); ncb = NUMCACHEBLKS(length+(phys & (SMP_CACHE_BYTES - 1))); dsc->dscr_a = phys | V_DMA_DSCRA_A_SIZE(ncb) |#ifndef CONFIG_SBMAC_COALESCE M_DMA_DSCRA_INTERRUPT |#endif M_DMA_ETHTX_SOP; /* transmitting: set outbound options and length */ dsc->dscr_b = V_DMA_DSCRB_OPTIONS(K_DMA_ETHTX_APPENDCRC_APPENDPAD) | V_DMA_DSCRB_PKT_SIZE(length); /* * fill in the context */ d->sbdma_ctxtable[dsc-d->sbdma_dscrtable] = sb; /* * point at next packet */ d->sbdma_addptr = nextdsc; /* * Give the buffer to the DMA engine. */ __raw_writeq(1, d->sbdma_dscrcnt); return 0; /* we did it */}/********************************************************************** * SBDMA_EMPTYRING(d) * * Free all allocated sk_buffs on the specified DMA channel; * * Input parameters: * d - DMA channel * * Return value: * nothing ********************************************************************* */static void sbdma_emptyring(struct sbmacdma *d){ int idx; struct sk_buff *sb; for (idx = 0; idx < d->sbdma_maxdescr; idx++) { sb = d->sbdma_ctxtable[idx]; if (sb) { dev_kfree_skb(sb); d->sbdma_ctxtable[idx] = NULL; } }}/********************************************************************** * SBDMA_FILLRING(d) * * Fill the specified DMA channel (must be receive channel) * with sk_buffs * * Input parameters: * d - DMA channel * * Return value: * nothing ********************************************************************* */static void sbdma_fillring(struct sbmacdma *d){ int idx; for (idx = 0; idx < SBMAC_MAX_RXDESCR-1; idx++) { if (sbdma_add_rcvbuffer(d,NULL) != 0) break; }}#ifdef CONFIG_NET_POLL_CONTROLLERstatic void sbmac_netpoll(struct net_device *netdev){ struct sbmac_softc *sc = netdev_priv(netdev); int irq = sc->sbm_dev->irq; __raw_writeq(0, sc->sbm_imr); sbmac_intr(irq, netdev);
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?