⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 fcc_enet.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 5 页
字号:
	if (s & PHY_STAT_FAULT)		printk(", remote fault");	printk(".\n");}static void mii_display_config(void *data){	struct net_device *dev = data;	volatile struct fcc_enet_private *fep = dev->priv;	uint s = fep->phy_status;	printk("%s: config: auto-negotiation ", dev->name);	if (s & PHY_CONF_ANE)		printk("on");	else		printk("off");	if (s & PHY_CONF_100FDX)		printk(", 100FDX");	if (s & PHY_CONF_100HDX)		printk(", 100HDX");	if (s & PHY_CONF_10FDX)		printk(", 10FDX");	if (s & PHY_CONF_10HDX)		printk(", 10HDX");	if (!(s & PHY_CONF_SPMASK))		printk(", No speed/duplex selected?");	if (s & PHY_CONF_LOOP)		printk(", loopback enabled");	printk(".\n");	fep->sequence_done = 1;}static void mii_relink(struct net_device *dev){	struct fcc_enet_private *fep = dev->priv;	int duplex = 0;	fep->old_link = fep->link;	fep->link = (fep->phy_status & PHY_STAT_LINK) ? 1 : 0;#ifdef MDIO_DEBUG	printk("  mii_relink:  link=%d\n", fep->link);#endif	if (fep->link) {		if (fep->phy_status		    & (PHY_STAT_100FDX | PHY_STAT_10FDX))			duplex = 1;		fcc_restart(dev, duplex);#ifdef MDIO_DEBUG		printk("  mii_relink:  duplex=%d\n", duplex);#endif	}}static void mii_queue_relink(uint mii_reg, struct net_device *dev){	struct fcc_enet_private *fep = dev->priv;	mii_relink(dev);	schedule_work(&fep->phy_relink);}static void mii_queue_config(uint mii_reg, struct net_device *dev){	struct fcc_enet_private *fep = dev->priv;	schedule_work(&fep->phy_display_config);}phy_cmd_t phy_cmd_relink[] = { { mk_mii_read(MII_BMCR), mii_queue_relink },			       { mk_mii_end, } };phy_cmd_t phy_cmd_config[] = { { mk_mii_read(MII_BMCR), mii_queue_config },			       { mk_mii_end, } };/* Read remainder of PHY ID.*/static voidmii_discover_phy3(uint mii_reg, struct net_device *dev){	struct fcc_enet_private *fep;	int	i;	fep = dev->priv;	printk("mii_reg: %08x\n", mii_reg);	fep->phy_id |= (mii_reg & 0xffff);	for(i = 0; phy_info[i]; i++)		if((phy_info[i]->id == (fep->phy_id >> 4)) || !phy_info[i]->id)			break;	if(!phy_info[i])		panic("%s: PHY id 0x%08x is not supported!\n",		      dev->name, fep->phy_id);	fep->phy = phy_info[i];	fep->phy_id_done = 1;	printk("%s: Phy @ 0x%x, type %s (0x%08x)\n",		dev->name, fep->phy_addr, fep->phy->name, fep->phy_id);}/* Scan all of the MII PHY addresses looking for someone to respond * with a valid ID.  This usually happens quickly. */static voidmii_discover_phy(uint mii_reg, struct net_device *dev){	struct fcc_enet_private *fep;	uint	phytype;	fep = dev->priv;	if ((phytype = (mii_reg & 0xffff)) != 0xffff) {		/* Got first part of ID, now get remainder. */		fep->phy_id = phytype << 16;		mii_queue(dev, mk_mii_read(MII_PHYSID2), mii_discover_phy3);	} else {		fep->phy_addr++;		if (fep->phy_addr < 32) {			mii_queue(dev, mk_mii_read(MII_PHYSID1),							mii_discover_phy);		} else {			printk("fec: No PHY device found.\n");		}	}}#endif	/* CONFIG_USE_MDIO */#ifdef PHY_INTERRUPT/* This interrupt occurs when the PHY detects a link change. */static irqreturn_tmii_link_interrupt(int irq, void * dev_id, struct pt_regs * regs){	struct	net_device *dev = dev_id;	struct fcc_enet_private *fep = dev->priv;	fcc_info_t *fip = fep->fip;	if (fep->phy) {		/* We don't want to be interrupted by an FCC		 * interrupt here.		 */		disable_irq_nosync(fip->fc_interrupt);		mii_do_cmd(dev, fep->phy->ack_int);		/* restart and display status */		mii_do_cmd(dev, phy_cmd_relink);		enable_irq(fip->fc_interrupt);	}	return IRQ_HANDLED;}#endif	/* ifdef PHY_INTERRUPT */#if 0 /* This should be fixed someday *//* 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 voidset_multicast_list(struct net_device *dev){	struct	fcc_enet_private *cep;	struct	dev_mc_list *dmi;	u_char	*mcptr, *tdptr;	volatile fcc_enet_t *ep;	int	i, j;	cep = (struct fcc_enet_private *)dev->priv;return;	/* Get pointer to FCC area in parameter RAM.	*/	ep = (fcc_enet_t *)dev->base_addr;	if (dev->flags&IFF_PROMISC) {			/* Log any net taps. */		printk("%s: Promiscuous mode enabled.\n", dev->name);		cep->fccp->fcc_fpsmr |= FCC_PSMR_PRO;	} else {		cep->fccp->fcc_fpsmr &= ~FCC_PSMR_PRO;		if (dev->flags & IFF_ALLMULTI) {			/* Catch all multicast addresses, so set the			 * filter to all 1's.			 */			ep->fen_gaddrh = 0xffffffff;			ep->fen_gaddrl = 0xffffffff;		}		else {			/* Clear filter and add the addresses in the list.			*/			ep->fen_gaddrh = 0;			ep->fen_gaddrl = 0;			dmi = dev->mc_list;			for (i=0; i<dev->mc_count; i++, dmi = dmi->next) {				/* 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->fen_taddrh;				for (j=0; j<6; j++)					*tdptr++ = *mcptr--;				/* Ask CPM to run CRC and set bit in				 * filter mask.				 */				cpmp->cp_cpcr = mk_cr_cmd(cep->fip->fc_cpmpage,						cep->fip->fc_cpmblock, 0x0c,						CPM_CR_SET_GADDR) | CPM_CR_FLG;				udelay(10);				while (cpmp->cp_cpcr & CPM_CR_FLG);			}		}	}}#endif /* if 0 *//* Set the individual MAC address. */int fcc_enet_set_mac_address(struct net_device *dev, void *p){	struct sockaddr *addr= (struct sockaddr *) p;	struct fcc_enet_private *cep;	volatile fcc_enet_t *ep;	unsigned char *eap;	int i;	cep = (struct fcc_enet_private *)(dev->priv);	ep = cep->ep;        if (netif_running(dev))                return -EBUSY;        memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);	eap = (unsigned char *) &(ep->fen_paddrh);	for (i=5; i>=0; i--)		*eap++ = addr->sa_data[i];        return 0;}/* Initialize the CPM Ethernet on FCC. */static int __init fec_enet_init(void){	struct net_device *dev;	struct fcc_enet_private *cep;	fcc_info_t	*fip;	int	i, np, err;	volatile	cpm2_map_t		*immap;	volatile	iop_cpm2_t	*io;	immap = (cpm2_map_t *)CPM_MAP_ADDR;	/* and to internal registers */	io = &immap->im_ioport;	np = sizeof(fcc_ports) / sizeof(fcc_info_t);	fip = fcc_ports;	while (np-- > 0) {		/* Create an Ethernet device instance.		*/		dev = alloc_etherdev(sizeof(*cep));		if (!dev)			return -ENOMEM;		cep = dev->priv;		spin_lock_init(&cep->lock);		cep->fip = fip;		init_fcc_shutdown(fip, cep, immap);		init_fcc_ioports(fip, io, immap);		init_fcc_param(fip, dev, immap);		dev->base_addr = (unsigned long)(cep->ep);		/* The CPM Ethernet specific entries in the device		 * structure.		 */		dev->open = fcc_enet_open;		dev->hard_start_xmit = fcc_enet_start_xmit;		dev->tx_timeout = fcc_enet_timeout;		dev->watchdog_timeo = TX_TIMEOUT;		dev->stop = fcc_enet_close;		dev->get_stats = fcc_enet_get_stats;		/* dev->set_multicast_list = set_multicast_list; */		dev->set_mac_address = fcc_enet_set_mac_address;		init_fcc_startup(fip, dev);		err = register_netdev(dev);		if (err) {			free_netdev(dev);			return err;		}		printk("%s: FCC 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]);#ifdef	CONFIG_USE_MDIO		/* Queue up command to detect the PHY and initialize the	 	* remainder of the interface.	 	*/		cep->phy_id_done = 0;		cep->phy_addr = fip->fc_phyaddr;		mii_queue(dev, mk_mii_read(MII_PHYSID1), mii_discover_phy);		INIT_WORK(&cep->phy_relink, mii_display_status, dev);		INIT_WORK(&cep->phy_display_config, mii_display_config, dev);#endif	/* CONFIG_USE_MDIO */		fip++;	}	return 0;}module_init(fec_enet_init);/* Make sure the device is shut down during initialization.*/static void __initinit_fcc_shutdown(fcc_info_t *fip, struct fcc_enet_private *cep,						volatile cpm2_map_t *immap){	volatile	fcc_enet_t	*ep;	volatile	fcc_t		*fccp;	/* Get pointer to FCC area in parameter RAM.	*/	ep = (fcc_enet_t *)(&immap->im_dprambase[fip->fc_proff]);	/* And another to the FCC register area.	*/	fccp = (volatile fcc_t *)(&immap->im_fcc[fip->fc_fccnum]);	cep->fccp = fccp;		/* Keep the pointers handy */	cep->ep = ep;	/* Disable receive and transmit in case someone left it running.	*/	fccp->fcc_gfmr &= ~(FCC_GFMR_ENR | FCC_GFMR_ENT);}/* Initialize the I/O pins for the FCC Ethernet.*/static void __initinit_fcc_ioports(fcc_info_t *fip, volatile iop_cpm2_t *io,						volatile cpm2_map_t *immap){	/* FCC1 pins are on port A/C.  FCC2/3 are port B/C.	*/	if (fip->fc_proff == PROFF_FCC1) {		/* Configure port A and C pins for FCC1 Ethernet.		 */		io->iop_pdira &= ~PA1_DIRA_BOUT;		io->iop_pdira |= PA1_DIRA_BIN;		io->iop_psora &= ~PA1_PSORA_BOUT;		io->iop_psora |= PA1_PSORA_BIN;		io->iop_ppara |= (PA1_DIRA_BOUT | PA1_DIRA_BIN);	}	if (fip->fc_proff == PROFF_FCC2) {		/* Configure port B and C pins for FCC Ethernet.		 */		io->iop_pdirb &= ~PB2_DIRB_BOUT;		io->iop_pdirb |= PB2_DIRB_BIN;		io->iop_psorb &= ~PB2_PSORB_BOUT;		io->iop_psorb |= PB2_PSORB_BIN;		io->iop_pparb |= (PB2_DIRB_BOUT | PB2_DIRB_BIN);	}	if (fip->fc_proff == PROFF_FCC3) {		/* Configure port B and C pins for FCC Ethernet.		 */		io->iop_pdirb &= ~PB3_DIRB_BOUT;		io->iop_pdirb |= PB3_DIRB_BIN;		io->iop_psorb &= ~PB3_PSORB_BOUT;		io->iop_psorb |= PB3_PSORB_BIN;		io->iop_pparb |= (PB3_DIRB_BOUT | PB3_DIRB_BIN);		io->iop_pdirc &= ~PC3_DIRC_BOUT;		io->iop_pdirc |= PC3_DIRC_BIN;		io->iop_psorc &= ~PC3_PSORC_BOUT;		io->iop_psorc |= PC3_PSORC_BIN;		io->iop_pparc |= (PC3_DIRC_BOUT | PC3_DIRC_BIN);	}	/* Port C has clocks......	*/	io->iop_psorc &= ~(fip->fc_trxclocks);	io->iop_pdirc &= ~(fip->fc_trxclocks);	io->iop_pparc |= fip->fc_trxclocks;#ifdef	CONFIG_USE_MDIO	/* ....and the MII serial clock/data.	*/	io->iop_pdatc |= (fip->fc_mdio | fip->fc_mdck);	io->iop_podrc &= ~(fip->fc_mdio | fip->fc_mdck);	io->iop_pdirc |= (fip->fc_mdio | fip->fc_mdck);	io->iop_pparc &= ~(fip->fc_mdio | fip->fc_mdck);#endif	/* CONFIG_USE_MDIO */	/* Configure Serial Interface clock routing.	 * First, clear all FCC bits to zero,	 * then set the ones we want.	 */	immap->im_cpmux.cmx_fcr &= ~(fip->fc_clockmask);	immap->im_cpmux.cmx_fcr |= fip->fc_clockroute;}static void __initinit_fcc_param(fcc_info_t *fip, struct net_device *dev,						volatile cpm2_map_t *immap){	unsigned char	*eap;	unsigned long	mem_addr;	bd_t		*bd;	int		i, j;	struct		fcc_enet_private *cep;	volatile	fcc_enet_t	*ep;	volatile	cbd_t		*bdp;	volatile	cpm_cpm2_t	*cp;	cep = (struct fcc_enet_private *)(dev->priv);	ep = cep->ep;	cp = cpmp;	bd = (bd_t *)__res;	/* Zero the whole thing.....I must have missed some individually.	 * It works when I do this.	 */	memset((char *)ep, 0, sizeof(fcc_enet_t));	/* Allocate space for the buffer descriptors from regular memory.	 * Initialize base addresses for the buffer descriptors.	 */	cep->rx_bd_base = (cbd_t *)kmalloc(sizeof(cbd_t) * RX_RING_SIZE,			GFP_KERNEL | GFP_DMA);	ep->fen_genfcc.fcc_rbase = __pa(cep->rx_bd_base);	cep->tx_bd_base = (cbd_t *)kmalloc(sizeof(cbd_t) * TX_RING_SIZE,			GFP_KERNEL | GFP_DMA);	ep->fen_genfcc.fcc_tbase = __pa(cep->tx_bd_base);	cep->dirty_tx = cep->cur_tx = cep->tx_bd_base;	cep->cur_rx = cep->rx_bd_base;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -