📄 sungem.c
字号:
gem_init_bcm5400_phy(gp); gp->gigabit_capable = 1; break; case 0x206050: printk("BCM 5401\n"); gp->phy_mod = phymod_bcm5401; gem_init_bcm5401_phy(gp); gp->gigabit_capable = 1; break; case 0x206070: printk("BCM 5411\n"); gp->phy_mod = phymod_bcm5411; gem_init_bcm5411_phy(gp); gp->gigabit_capable = 1; break; case 0x1410c60: printk("M1011 (Marvel ?)\n"); gp->phy_mod = phymod_m1011; gp->gigabit_capable = 1; break; case 0x18074c0: printk("Lucent\n"); gp->phy_mod = phymod_generic; break; case 0x437420: printk("Enable Semiconductor\n"); gp->phy_mod = phymod_generic; break; default: printk("Unknown (Using generic mode)\n"); gp->phy_mod = phymod_generic; break; }; /* Init advertisement and enable autonegotiation. */ val = phy_read(gp, MII_BMCR); val &= ~BMCR_ANENABLE; phy_write(gp, MII_BMCR, val); udelay(10); phy_write(gp, MII_ADVERTISE, phy_read(gp, MII_ADVERTISE) | (ADVERTISE_10HALF | ADVERTISE_10FULL | ADVERTISE_100HALF | ADVERTISE_100FULL)); } else { u32 val; int limit; /* Reset PCS unit. */ val = readl(gp->regs + PCS_MIICTRL); val |= PCS_MIICTRL_RST; writeb(val, gp->regs + PCS_MIICTRL); limit = 32; while (readl(gp->regs + PCS_MIICTRL) & PCS_MIICTRL_RST) { udelay(100); if (limit-- <= 0) break; } if (limit <= 0) printk(KERN_WARNING "%s: PCS reset bit would not clear.\n", gp->dev->name); /* Make sure PCS is disabled while changing advertisement * configuration. */ val = readl(gp->regs + PCS_CFG); val &= ~(PCS_CFG_ENABLE | PCS_CFG_TO); writel(val, gp->regs + PCS_CFG); /* Advertise all capabilities. */ val = readl(gp->regs + PCS_MIIADV); val |= (PCS_MIIADV_FD | PCS_MIIADV_HD | PCS_MIIADV_SP | PCS_MIIADV_AP); writel(val, gp->regs + PCS_MIIADV); /* Enable and restart auto-negotiation, disable wrapback/loopback, * and re-enable PCS. */ val = readl(gp->regs + PCS_MIICTRL); val |= (PCS_MIICTRL_RAN | PCS_MIICTRL_ANE); val &= ~PCS_MIICTRL_WB; writel(val, gp->regs + PCS_MIICTRL); val = readl(gp->regs + PCS_CFG); val |= PCS_CFG_ENABLE; writel(val, gp->regs + PCS_CFG); /* Make sure serialink loopback is off. The meaning * of this bit is logically inverted based upon whether * you are in Serialink or SERDES mode. */ val = readl(gp->regs + PCS_SCTRL); if (gp->phy_type == phy_serialink) val &= ~PCS_SCTRL_LOOP; else val |= PCS_SCTRL_LOOP; writel(val, gp->regs + PCS_SCTRL); gp->gigabit_capable = 1; } /* BMCR_SPD2 is a broadcom 54xx specific thing afaik */ if (gp->phy_mod != phymod_bcm5400 && gp->phy_mod != phymod_bcm5401 && gp->phy_mod != phymod_bcm5411) gp->link_cntl &= ~BMCR_SPD2; }static void gem_init_dma(struct gem *gp){ u64 desc_dma = (u64) gp->gblock_dvma; u32 val; val = (TXDMA_CFG_BASE | (0x7ff << 10) | TXDMA_CFG_PMODE); writel(val, gp->regs + TXDMA_CFG); writel(desc_dma >> 32, gp->regs + TXDMA_DBHI); writel(desc_dma & 0xffffffff, gp->regs + TXDMA_DBLOW); desc_dma += (INIT_BLOCK_TX_RING_SIZE * sizeof(struct gem_txd)); writel(0, gp->regs + TXDMA_KICK); val = (RXDMA_CFG_BASE | (RX_OFFSET << 10) | ((14 / 2) << 13) | RXDMA_CFG_FTHRESH_512); writel(val, gp->regs + RXDMA_CFG); writel(desc_dma >> 32, gp->regs + RXDMA_DBHI); writel(desc_dma & 0xffffffff, gp->regs + RXDMA_DBLOW); writel(RX_RING_SIZE - 4, gp->regs + RXDMA_KICK); val = (((gp->rx_pause_off / 64) << 0) & RXDMA_PTHRESH_OFF); val |= (((gp->rx_pause_on / 64) << 12) & RXDMA_PTHRESH_ON); writel(val, gp->regs + RXDMA_PTHRESH); if (readl(gp->regs + GREG_BIFCFG) & GREG_BIFCFG_M66EN) writel(((5 & RXDMA_BLANK_IPKTS) | ((8 << 12) & RXDMA_BLANK_ITIME)), gp->regs + RXDMA_BLANK); else writel(((5 & RXDMA_BLANK_IPKTS) | ((4 << 12) & RXDMA_BLANK_ITIME)), gp->regs + RXDMA_BLANK);}#define CRC_POLYNOMIAL_LE 0xedb88320UL /* Ethernet CRC, little endian */static u32gem_setup_multicast(struct gem *gp){ u32 rxcfg = 0; int i; if ((gp->dev->flags & IFF_ALLMULTI) || (gp->dev->mc_count > 256)) { for (i=0; i<16; i++) writel(0xffff, gp->regs + MAC_HASH0 + (i << 2)); rxcfg |= MAC_RXCFG_HFE; } else if (gp->dev->flags & IFF_PROMISC) { rxcfg |= MAC_RXCFG_PROM; } else { u16 hash_table[16]; u32 crc, poly = CRC_POLYNOMIAL_LE; struct dev_mc_list *dmi = gp->dev->mc_list; int i, j, bit, byte; for (i = 0; i < 16; i++) hash_table[i] = 0; for (i = 0; i < gp->dev->mc_count; i++) { char *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 >>= 24; hash_table[crc >> 4] |= 1 << (15 - (crc & 0xf)); } for (i=0; i<16; i++) writel(hash_table[i], gp->regs + MAC_HASH0 + (i << 2)); rxcfg |= MAC_RXCFG_HFE; } return rxcfg;}static void gem_init_mac(struct gem *gp){ unsigned char *e = &gp->dev->dev_addr[0]; u32 rxcfg; if (gp->pdev->vendor == PCI_VENDOR_ID_SUN && gp->pdev->device == PCI_DEVICE_ID_SUN_GEM) writel(0x1bf0, gp->regs + MAC_SNDPAUSE); writel(0x00, gp->regs + MAC_IPG0); writel(0x08, gp->regs + MAC_IPG1); writel(0x04, gp->regs + MAC_IPG2); writel(0x40, gp->regs + MAC_STIME); writel(0x40, gp->regs + MAC_MINFSZ); writel(0x20000000 | (gp->dev->mtu + 18), gp->regs + MAC_MAXFSZ); writel(0x07, gp->regs + MAC_PASIZE); writel(0x04, gp->regs + MAC_JAMSIZE); writel(0x10, gp->regs + MAC_ATTLIM); writel(0x8808, gp->regs + MAC_MCTYPE); writel((e[5] | (e[4] << 8)) & 0x3ff, gp->regs + MAC_RANDSEED); writel((e[4] << 8) | e[5], gp->regs + MAC_ADDR0); writel((e[2] << 8) | e[3], gp->regs + MAC_ADDR1); writel((e[0] << 8) | e[1], gp->regs + MAC_ADDR2); writel(0, gp->regs + MAC_ADDR3); writel(0, gp->regs + MAC_ADDR4); writel(0, gp->regs + MAC_ADDR5); writel(0x0001, gp->regs + MAC_ADDR6); writel(0xc200, gp->regs + MAC_ADDR7); writel(0x0180, gp->regs + MAC_ADDR8); writel(0, gp->regs + MAC_AFILT0); writel(0, gp->regs + MAC_AFILT1); writel(0, gp->regs + MAC_AFILT2); writel(0, gp->regs + MAC_AF21MSK); writel(0, gp->regs + MAC_AF0MSK); rxcfg = gem_setup_multicast(gp); writel(0, gp->regs + MAC_NCOLL); writel(0, gp->regs + MAC_FASUCC); writel(0, gp->regs + MAC_ECOLL); writel(0, gp->regs + MAC_LCOLL); writel(0, gp->regs + MAC_DTIMER); writel(0, gp->regs + MAC_PATMPS); writel(0, gp->regs + MAC_RFCTR); writel(0, gp->regs + MAC_LERR); writel(0, gp->regs + MAC_AERR); writel(0, gp->regs + MAC_FCSERR); writel(0, gp->regs + MAC_RXCVERR); /* Clear RX/TX/MAC/XIF config, we will set these up and enable * them once a link is established. */ writel(0, gp->regs + MAC_TXCFG); writel(rxcfg, gp->regs + MAC_RXCFG); writel(0, gp->regs + MAC_MCCFG); writel(0, gp->regs + MAC_XIFCFG); /* Setup MAC interrupts. We want to get all of the interesting * counter expiration events, but we do not want to hear about * normal rx/tx as the DMA engine tells us that. */ writel(MAC_TXSTAT_XMIT, gp->regs + MAC_TXMASK); writel(MAC_RXSTAT_RCV, gp->regs + MAC_RXMASK); /* Don't enable even the PAUSE interrupts for now, we * make no use of those events other than to record them. */ writel(0xffffffff, gp->regs + MAC_MCMASK);}static void gem_init_pause_thresholds(struct gem *gp){ /* Calculate pause thresholds. Setting the OFF threshold to the * full RX fifo size effectively disables PAUSE generation which * is what we do for 10/100 only GEMs which have FIFOs too small * to make real gains from PAUSE. */ if (gp->rx_fifo_sz <= (2 * 1024)) { gp->rx_pause_off = gp->rx_pause_on = gp->rx_fifo_sz; } else { int off = (gp->rx_fifo_sz - (5 * 1024)); int on = off - 1024; gp->rx_pause_off = off; gp->rx_pause_on = on; } { u32 cfg; cfg = GREG_CFG_IBURST; cfg |= ((31 << 1) & GREG_CFG_TXDMALIM); cfg |= ((31 << 6) & GREG_CFG_RXDMALIM); writel(cfg, gp->regs + GREG_CFG); }}static int gem_check_invariants(struct gem *gp){ struct pci_dev *pdev = gp->pdev; u32 mif_cfg; /* On Apple's sungem, we can't rely on registers as the chip * was been powered down by the firmware. The PHY is looked * up later on. */ if (pdev->vendor == PCI_VENDOR_ID_APPLE) { gp->phy_type = phy_mii_mdio0; gp->tx_fifo_sz = readl(gp->regs + TXDMA_FSZ) * 64; gp->rx_fifo_sz = readl(gp->regs + RXDMA_FSZ) * 64; return 0; } mif_cfg = readl(gp->regs + MIF_CFG); if (pdev->vendor == PCI_VENDOR_ID_SUN && pdev->device == PCI_DEVICE_ID_SUN_RIO_GEM) { /* One of the MII PHYs _must_ be present * as this chip has no gigabit PHY. */ if ((mif_cfg & (MIF_CFG_MDI0 | MIF_CFG_MDI1)) == 0) { printk(KERN_ERR PFX "RIO GEM lacks MII phy, mif_cfg[%08x]\n", mif_cfg); return -1; } } /* Determine initial PHY interface type guess. MDIO1 is the * external PHY and thus takes precedence over MDIO0. */ if (mif_cfg & MIF_CFG_MDI1) { gp->phy_type = phy_mii_mdio1; mif_cfg |= MIF_CFG_PSELECT; writel(mif_cfg, gp->regs + MIF_CFG); } else if (mif_cfg & MIF_CFG_MDI0) { gp->phy_type = phy_mii_mdio0; mif_cfg &= ~MIF_CFG_PSELECT; writel(mif_cfg, gp->regs + MIF_CFG); } else { gp->phy_type = phy_serialink; } if (gp->phy_type == phy_mii_mdio1 || gp->phy_type == phy_mii_mdio0) { int i; for (i = 0; i < 32; i++) { gp->mii_phy_addr = i; if (phy_read(gp, MII_BMCR) != 0xffff) break; } if (i == 32) { if (pdev->device != PCI_DEVICE_ID_SUN_GEM) { printk(KERN_ERR PFX "RIO MII phy will not respond.\n"); return -1; } gp->phy_type = phy_serdes; } } /* Fetch the FIFO configurations now too. */ gp->tx_fifo_sz = readl(gp->regs + TXDMA_FSZ) * 64; gp->rx_fifo_sz = readl(gp->regs + RXDMA_FSZ) * 64; if (pdev->vendor == PCI_VENDOR_ID_SUN) { if (pdev->device == PCI_DEVICE_ID_SUN_GEM) { if (gp->tx_fifo_sz != (9 * 1024) || gp->rx_fifo_sz != (20 * 1024)) { printk(KERN_ERR PFX "GEM has bogus fifo sizes tx(%d) rx(%d)\n", gp->tx_fifo_sz, gp->rx_fifo_sz); return -1; } } else { if (gp->tx_fifo_sz != (2 * 1024) || gp->rx_fifo_sz != (2 * 1024)) { printk(KERN_ERR PFX "RIO GEM has bogus fifo sizes tx(%d) rx(%d)\n", gp->tx_fifo_sz, gp->rx_fifo_sz); return -1; } } } return 0;}static void gem_init_hw(struct gem *gp, int restart_link){ /* On Apple's gmac, I initialize the PHY only after * setting up the chip. It appears the gigabit PHYs * don't quite like beeing talked to on the GII when * the chip is not running, I suspect it might not * be clocked at that point. --BenH */ if (restart_link) gem_init_phy(gp); gem_init_dma(gp); gem_init_mac(gp); gem_init_pause_thresholds(gp); spin_lock_irq(&gp->lock); if (restart_link) { /* Default aneg parameters */ gp->timer_ticks = 0; gp->lstate = link_down; spin_unlock_irq(&gp->lock); /* Can I advertise gigabit here ? I'd need BCM PHY docs... */ gem_begin_auto_negotiation(gp, NULL); } else { if (gp->lstate == link_up) gem_set_link_modes(gp); spin_unlock_irq(&gp->lock); }}#ifdef CONFIG_ALL_PPC/* Enable the chip's clock and make sure it's config space is * setup properly. There appear to be no need to restore the * base addresses. */static void gem_apple_powerup(struct gem *gp){ u16 cmd; u32 mif_cfg; pmac_call_feature(PMAC_FTR_GMAC_ENABLE, gp->of_node, 0, 1); current->state = TASK_UNINTERRUPTIBLE; schedule_timeout((21 * HZ) / 1000); pci_read_config_word(gp->pdev, PCI_COMMAND, &cmd); cmd |= PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER | PCI_COMMAND_INVALIDATE; pci_write_config_word(gp->pdev, PCI_COMMAND, cmd); pci_write_config_byte(gp->pdev, PCI_LATENCY_TIMER, 6); pci_write_config_byte(gp->pdev, PCI_CACHE_LINE_SIZE, 8); mdelay(1); mif_cfg = readl(gp->regs + MIF_CFG); mif_cfg &= ~(MIF_CFG_PSELECT|MIF_CFG_POLL|MIF_CFG_BBMODE|MIF_CFG_MDI1); mif_cfg |= MIF_CFG_MDI0; writel(mif_cfg, gp->regs + MIF_CFG); writel(PCS_DMODE_MGM, gp->regs + PCS_DMODE); writel(MAC_XIFCFG_OE, gp->regs + MAC_XIFCFG); mdelay(1);}/* Turn off the chip's clock */static void gem_apple_powerdown(struct gem *gp){ pmac_call_feature(PMAC_FTR_GMAC_ENABLE, gp->of_node, 0, 0);}#endif /* CONFIG_ALL_PPC */static void gem_stop_phy(struct gem *gp){ u32 mifcfg; if (!gp->wake_on_lan && gp->phy_mod == phymod_bcm5201) phy_write(gp, MII_BCM5201_INTERRUPT, 0); /* Make sure we aren't polling PHY status change. We * don't currently use that feature though */ mifcfg = readl(gp->regs + MIF_CFG); mifcfg &= ~MIF_CFG_POLL; writel(mifcfg, gp->regs + MIF_CFG); /* Here's a strange hack used by both MacOS 9 and X */ phy_write(gp, MII_LPA, phy_read(gp, MII_LPA)); if (gp->wake_on_lan) { /* Setup wake-on-lan */ } else writel(0, gp->regs + MAC_RXCFG); writel(0, gp->regs + MAC_TXCFG); writel(0, gp->regs + MAC_XIFCFG); writel(0, gp->regs + TXDMA_CFG); writel(0, gp->regs + RXDMA_CFG); if (!gp->wake_on_lan) { gem_stop(gp); writel(MAC_TXRST_CMD, gp->regs + MAC_TXRST); writel(MAC_RXRST_CMD, gp->regs + MAC_RXRST); if (gp->phy_mod == phymod_bcm5400 || gp->phy_mod == phymod_bcm5401 || gp->phy_mod == phymod_bcm5411) {#if 0 /* Commented out in Darwin... someone has those dawn docs ? */ phy_write(gp, MII_BMCR, BMCR_PDOWN);#endif } else if (gp->phy_mod == phymod_bcm5201 || gp->phy_mod == phymod_bcm5221) {#if 0 /* Commented out in Darwin... someone has those dawn docs ? */ u16 val = phy_read(gp, MII_BCM5201_AUXMODE2) phy_write(gp, MII_BCM5201_AUXMODE2, val & ~MII_BCM5201_AUXMODE2_LOWPOWER);#endif phy_write(gp, MII_BCM5201_MULTIPHY, MII_BCM5201_MULTIPHY_SUPERISOLATE); } else if (gp->phy_mod == phymod_m1011) phy_write(gp, MII_BMCR, BMCR_PDOWN); /* According to Apple, we must set the MDIO pins to this begnign * state or we may 1) eat more current, 2) damage some PHYs */ writel(mifcfg | MIF_CFG_BBMODE, gp->regs + MIF_CFG); writel(0, gp->regs + MIF_BBCLK); writel(0, gp->regs + MIF_BBDATA); writel(0, gp->regs + MIF_BBOENAB); writel(MAC_XIFCFG_GMII | MAC_XIFCFG_LBCK, gp->regs + MAC_XIFCFG); (void) readl(gp->regs + MAC_XIFCFG); }}/* Shut down the chip, must be called with pm_sem held. */static void gem_shutdown(struct gem *gp){
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -