sunqe.c

来自「powerpc内核mpc8241linux系统下net驱动程序」· C语言 代码 · 共 1,244 行 · 第 1/3 页

C
1,244
字号
}#define CRC_POLYNOMIAL_BE 0x04c11db7UL  /* Ethernet CRC, big endian */#define CRC_POLYNOMIAL_LE 0xedb88320UL  /* Ethernet CRC, little endian */static void qe_set_multicast(struct device *dev){	struct sunqe *qep = (struct sunqe *) dev->priv;	struct dev_mc_list *dmi = dev->mc_list;	unsigned char new_mconfig = (MREGS_MCONFIG_TXENAB | MREGS_MCONFIG_RXENAB);	char *addrs;	int i, j, bit, byte;	u32 crc, poly = CRC_POLYNOMIAL_LE;	/* Lock out others. */	set_bit(0, (void *) &dev->tbusy);	if((dev->flags & IFF_ALLMULTI) || (dev->mc_count > 64)) {		qep->mregs->iaconfig = MREGS_IACONFIG_ACHNGE | MREGS_IACONFIG_LARESET;		for(i = 0; i < 8; i++)			qep->mregs->filter = 0xff;		qep->mregs->iaconfig = 0;	} else if(dev->flags & IFF_PROMISC) {		new_mconfig |= MREGS_MCONFIG_PROMISC;	} else {		u16 hash_table[4];		unsigned char *hbytes = (unsigned char *) &hash_table[0];		for(i = 0; i < 4; i++)			hash_table[i] = 0;		for(i = 0; i < dev->mc_count; i++) {			addrs = dmi->dmi_addr;			dmi = dmi->next;			if(!(*addrs & 1))				continue;			crc = 0xffffffffU;			for(byte = 0; byte < 6; byte++) {				for(bit = *addrs++, j = 0; j < 8; j++, bit >>= 1) {					int test;					test = ((bit ^ crc) & 0x01);					crc >>= 1;					if(test)						crc = crc ^ poly;				}			}			crc >>= 26;			hash_table[crc >> 4] |= 1 << (crc & 0xf);		}		/* Program the qe with the new filter value. */		qep->mregs->iaconfig = MREGS_IACONFIG_ACHNGE | MREGS_IACONFIG_LARESET;		for(i = 0; i < 8; i++)			qep->mregs->filter = *hbytes++;		qep->mregs->iaconfig = 0;	}	/* Any change of the logical address filter, the physical address,	 * or enabling/disabling promiscuous mode causes the MACE to disable	 * the receiver.  So we must re-enable them here or else the MACE	 * refuses to listen to anything on the network.  Sheesh, took	 * me a day or two to find this bug.	 */	qep->mregs->mconfig = new_mconfig;	/* Let us get going again. */	dev->tbusy = 0;}/* This is only called once at boot time for each card probed. */static inline void qec_init_once(struct sunqec *qecp, struct linux_sbus_device *qsdev){	unsigned char bsizes = qecp->qec_bursts;	if(bsizes & DMA_BURST32)		qecp->gregs->ctrl = GLOB_CTRL_B32;	else		qecp->gregs->ctrl = GLOB_CTRL_B16;	/* Packetsize only used in 100baseT BigMAC configurations,	 * set it to zero just to be on the safe side.	 */	qecp->gregs->psize = 0;	/* Set the local memsize register, divided up to one piece per QE channel. */	qecp->gregs->msize = (qsdev->reg_addrs[1].reg_size >> 2);	/* Divide up the local QEC memory amongst the 4 QE receiver and	 * transmitter FIFOs.  Basically it is (total / 2 / num_channels).	 */	qecp->gregs->rsize = qecp->gregs->tsize =		(qsdev->reg_addrs[1].reg_size >> 2) >> 1;}/* Four QE's per QEC card. */static inline int qec_ether_init(struct device *dev, struct linux_sbus_device *sdev){	static unsigned version_printed = 0;	struct device *qe_devs[4];	struct sunqe *qeps[4];	struct linux_sbus_device *qesdevs[4];	struct sunqec *qecp;	struct linux_prom_ranges qranges[8];	unsigned char bsizes, bsizes_more, num_qranges;	int i, j, res = ENOMEM;	dev = init_etherdev(0, sizeof(struct sunqe));	qe_devs[0] = dev;	qeps[0] = (struct sunqe *) dev->priv;	qeps[0]->channel = 0;	for(j = 0; j < 6; j++)		qe_devs[0]->dev_addr[j] = idprom->id_ethaddr[j];	if(version_printed++ == 0)		printk(version);	qe_devs[1] = qe_devs[2] = qe_devs[3] = NULL;	for(i = 1; i < 4; i++) {		qe_devs[i] = init_etherdev(0, sizeof(struct sunqe));		if(qe_devs[i] == NULL || qe_devs[i]->priv == NULL)			goto qec_free_devs;		qeps[i] = (struct sunqe *) qe_devs[i]->priv;		for(j = 0; j < 6; j++)			qe_devs[i]->dev_addr[j] = idprom->id_ethaddr[j];		qeps[i]->channel = i;	}	qecp = kmalloc(sizeof(struct sunqec), GFP_KERNEL);	if(qecp == NULL)		goto qec_free_devs;	qecp->qec_sbus_dev = sdev;	for(i = 0; i < 4; i++) {		qecp->qes[i] = qeps[i];		qeps[i]->dev = qe_devs[i];		qeps[i]->parent = qecp;	}	/* Link in channel 0. */	i = prom_getintdefault(sdev->child->prom_node, "channel#", -1);	if(i == -1) { res=ENODEV; goto qec_free_devs; }	qesdevs[i] = sdev->child;	qe_devs[i]->base_addr = (long) qesdevs[i];	/* Link in channel 1. */	i = prom_getintdefault(sdev->child->next->prom_node, "channel#", -1);	if(i == -1) { res=ENODEV; goto qec_free_devs; }	qesdevs[i] = sdev->child->next;	qe_devs[i]->base_addr = (long) qesdevs[i];	/* Link in channel 2. */	i = prom_getintdefault(sdev->child->next->next->prom_node, "channel#", -1);	if(i == -1) { res=ENODEV; goto qec_free_devs; }	qesdevs[i] = sdev->child->next->next;	qe_devs[i]->base_addr = (long) qesdevs[i];	/* Link in channel 3. */	i = prom_getintdefault(sdev->child->next->next->next->prom_node, "channel#", -1);	if(i == -1) { res=ENODEV; goto qec_free_devs; }	qesdevs[i] = sdev->child->next->next->next;	qe_devs[i]->base_addr = (long) qesdevs[i];	for(i = 0; i < 4; i++)		qeps[i]->qe_sbusdev = qesdevs[i];	/* This is a bit of fun, get QEC ranges. */	i = prom_getproperty(sdev->prom_node, "ranges",			     (char *) &qranges[0], sizeof(qranges));	num_qranges = (i / sizeof(struct linux_prom_ranges));	/* Now, apply all the ranges, QEC ranges then the SBUS ones for each QE. */	for(i = 0; i < 4; i++) {		for(j = 0; j < 2; j++) {			int k;			for(k = 0; k < num_qranges; k++)				if(qesdevs[i]->reg_addrs[j].which_io ==				   qranges[k].ot_child_space)					break;			if(k >= num_qranges)				printk("QuadEther: Aieee, bogus QEC range for "				       "space %08x\n",qesdevs[i]->reg_addrs[j].which_io);			qesdevs[i]->reg_addrs[j].which_io = qranges[k].ot_parent_space;			qesdevs[i]->reg_addrs[j].phys_addr += qranges[k].ot_parent_base;		}		prom_apply_sbus_ranges(qesdevs[i]->my_bus, &qesdevs[i]->reg_addrs[0],				       2, qesdevs[i]);	}	/* Now map in the registers, QEC globals first. */	prom_apply_sbus_ranges(sdev->my_bus, &sdev->reg_addrs[0],			       sdev->num_registers, sdev);	qecp->gregs = sparc_alloc_io(sdev->reg_addrs[0].phys_addr, 0,				     sizeof(struct qe_globreg),				     "QEC Global Registers",				     sdev->reg_addrs[0].which_io, 0);	if(!qecp->gregs) {		printk("QuadEther: Cannot map QEC global registers.\n");		res = ENODEV;		goto qec_free_devs;	}	/* Make sure the QEC is in MACE mode. */	if((qecp->gregs->ctrl & 0xf0000000) != GLOB_CTRL_MMODE) {		printk("QuadEther: AIEEE, QEC is not in MACE mode!\n");		res = ENODEV;		goto qec_free_devs;	}	/* Reset the QEC. */	if(qec_global_reset(qecp->gregs)) {		res = ENODEV;		goto qec_free_devs;	}	/* Find and set the burst sizes for the QEC, since it does	 * the actual dma for all 4 channels.	 */	bsizes = prom_getintdefault(sdev->prom_node, "burst-sizes", 0xff);	bsizes &= 0xff;	bsizes_more = prom_getintdefault(sdev->my_bus->prom_node, "burst-sizes", 0xff);	if(bsizes_more != 0xff)		bsizes &= bsizes_more;	if(bsizes == 0xff || (bsizes & DMA_BURST16) == 0 ||	   (bsizes & DMA_BURST32)==0)		bsizes = (DMA_BURST32 - 1);	qecp->qec_bursts = bsizes;	/* Perform one time QEC initialization, we never touch the QEC	 * globals again after this.	 */	qec_init_once(qecp, sdev);	for(i = 0; i < 4; i++) {		/* Map in QEC per-channel control registers. */		qeps[i]->qcregs = sparc_alloc_io(qesdevs[i]->reg_addrs[0].phys_addr, 0,						 sizeof(struct qe_creg),						 "QEC Per-Channel Registers",						 qesdevs[i]->reg_addrs[0].which_io, 0);		if(!qeps[i]->qcregs) {			printk("QuadEther: Cannot map QE %d's channel registers.\n", i);			res = ENODEV;			goto qec_free_devs;		}		/* Map in per-channel AMD MACE registers. */		qeps[i]->mregs = sparc_alloc_io(qesdevs[i]->reg_addrs[1].phys_addr, 0,						sizeof(struct qe_mregs),						"QE MACE Registers",						qesdevs[i]->reg_addrs[1].which_io, 0);		if(!qeps[i]->mregs) {			printk("QuadEther: Cannot map QE %d's MACE registers.\n", i);			res = ENODEV;			goto qec_free_devs;		}		qeps[i]->qe_block = (struct qe_init_block *)			sparc_dvma_malloc(PAGE_SIZE, "QE Init Block",					  &qeps[i]->qblock_dvma);		if(sparc_cpu_model == sun4c)			qeps[i]->sun4c_buffers = (struct sunqe_buffers *)				sparc_dvma_malloc(sizeof(struct sunqe_buffers),						  "QE RX/TX Buffers",						  &qeps[i]->s4c_buf_dvma);		else			qeps[i]->sun4c_buffers = 0;		/* Stop this QE. */		qe_stop(qeps[i]);	}	for(i = 0; i < 4; i++) {		qe_devs[i]->open = qe_open;		qe_devs[i]->stop = qe_close;		if(sparc_cpu_model == sun4c)			qe_devs[i]->hard_start_xmit = sun4c_qe_start_xmit;		else			qe_devs[i]->hard_start_xmit = qe_start_xmit;		qe_devs[i]->get_stats = qe_get_stats;		qe_devs[i]->set_multicast_list = qe_set_multicast;		qe_devs[i]->irq = sdev->irqs[0];		qe_devs[i]->dma = 0;		ether_setup(qe_devs[i]);	}	/* QEC receives interrupts from each QE, then it send the actual	 * IRQ to the cpu itself.  Since QEC is the single point of	 * interrupt for all QE channels we register the IRQ handler	 * for it now.	 */	if(sparc_cpu_model == sun4c) {		if(request_irq(sdev->irqs[0], &sun4c_qec_interrupt,			       SA_SHIRQ, "QuadEther", (void *) qecp)) {			printk("QuadEther: Can't register QEC master irq handler.\n");			res = EAGAIN;			goto qec_free_devs;		}	} else {		if(request_irq(sdev->irqs[0], &qec_interrupt,			       SA_SHIRQ, "QuadEther", (void *) qecp)) {			printk("QuadEther: Can't register QEC master irq handler.\n");			res = EAGAIN;			goto qec_free_devs;		}	}	/* Report the QE channels. */	for(i = 0; i < 4; i++) {		printk("%s: QuadEthernet channel[%d] ", qe_devs[i]->name, i);		for(j = 0; j < 6; j++)			printk ("%2.2x%c",				qe_devs[i]->dev_addr[j],				j == 5 ? ' ': ':');		printk("\n");	}#ifdef MODULE	/* We are home free at this point, link the qe's into	 * the master list for later module unloading.	 */	for(i = 0; i < 4; i++)		qe_devs[i]->ifindex = dev_new_index();	qecp->next_module = root_qec_dev;	root_qec_dev = qecp;#endif	return 0;qec_free_devs:	for(i = 0; i < 4; i++) {		if(qe_devs[i]) {			if(qe_devs[i]->priv)				kfree(qe_devs[i]->priv);			kfree(qe_devs[i]);		}	}	return res;}__initfunc(int qec_probe(struct device *dev)){	struct linux_sbus *bus;	struct linux_sbus_device *sdev = 0;	static int called = 0;	int cards = 0, v;	if(called)		return ENODEV;	called++;	for_each_sbus(bus) {		for_each_sbusdev(sdev, bus) {			if(cards) dev = NULL;			/* QEC can be parent of either QuadEthernet or BigMAC			 * children.			 */			if(!strcmp(sdev->prom_name, "qec") && sdev->child &&			   !strcmp(sdev->child->prom_name, "qe") &&			   sdev->child->next &&			   !strcmp(sdev->child->next->prom_name, "qe") &&			   sdev->child->next->next &&			   !strcmp(sdev->child->next->next->prom_name, "qe") &&			   sdev->child->next->next->next &&			   !strcmp(sdev->child->next->next->next->prom_name, "qe")) {				cards++;				if((v = qec_ether_init(dev, sdev)))					return v;			}		}	}	if(!cards)		return ENODEV;	return 0;}#ifdef MODULEintinit_module(void){	root_qec_dev = NULL;	return qec_probe(NULL);}voidcleanup_module(void){	struct sunqec *next_qec;	int i;	/* No need to check MOD_IN_USE, as sys_delete_module() checks. */	while (root_qec_dev) {		next_qec = root_qec_dev->next_module;		/* Release all four QE channels, then the QEC itself. */		for(i = 0; i < 4; i++) {			unregister_netdev(root_qec_dev->qes[i]->dev);			kfree(root_qec_dev->qes[i]);		}		free_irq(root_qec_dev->qec_sbus_dev->irqs[0], (void *)root_qec_dev);		kfree(root_qec_dev);		root_qec_dev = next_qec;	}}#endif /* MODULE */

⌨️ 快捷键说明

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