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