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 + -
显示快捷键?