📄 forcedeth.c
字号:
writel(NVREG_TXRXCTL_BIT2, base + NvRegTxRxControl); pci_push(base);}/* * alloc_rx: fill rx ring entries. * Return 1 if the allocations for the skbs failed and the * rx engine is without Available descriptors */static int alloc_rx(struct nic *nic __unused){ unsigned int refill_rx = np->refill_rx; int i; //while (np->cur_rx != refill_rx) { for (i = 0; i < RX_RING; i++) { //int nr = refill_rx % RX_RING; rx_ring[i].PacketBuffer = virt_to_le32desc(&rxb[i * RX_NIC_BUFSIZE]); rx_ring[i].Length = cpu_to_le16(RX_NIC_BUFSIZE); wmb(); rx_ring[i].Flags = cpu_to_le16(NV_RX_AVAIL); /* printf("alloc_rx: Packet %d marked as Available\n", refill_rx); */ refill_rx++; } np->refill_rx = refill_rx; if (np->cur_rx - refill_rx == RX_RING) return 1; return 0;}static int update_linkspeed(struct nic *nic){ int adv, lpa, newdup; u32 newls; adv = mii_rw(nic, np->phyaddr, MII_ADVERTISE, MII_READ); lpa = mii_rw(nic, np->phyaddr, MII_LPA, MII_READ); dprintf(("update_linkspeed: PHY advertises 0x%hX, lpa 0x%hX.\n", adv, lpa)); /* FIXME: handle parallel detection properly, handle gigabit ethernet */ lpa = lpa & adv; if (lpa & LPA_100FULL) { newls = NVREG_LINKSPEED_FORCE | NVREG_LINKSPEED_100; newdup = 1; } else if (lpa & LPA_100HALF) { newls = NVREG_LINKSPEED_FORCE | NVREG_LINKSPEED_100; newdup = 0; } else if (lpa & LPA_10FULL) { newls = NVREG_LINKSPEED_FORCE | NVREG_LINKSPEED_10; newdup = 1; } else if (lpa & LPA_10HALF) { newls = NVREG_LINKSPEED_FORCE | NVREG_LINKSPEED_10; newdup = 0; } else { printf("bad ability %hX - falling back to 10HD.\n", lpa); newls = NVREG_LINKSPEED_FORCE | NVREG_LINKSPEED_10; newdup = 0; } if (np->duplex != newdup || np->linkspeed != newls) { np->duplex = newdup; np->linkspeed = newls; return 1; } return 0;}static int init_ring(struct nic *nic){ int i; np->next_tx = np->nic_tx = 0; for (i = 0; i < TX_RING; i++) { tx_ring[i].Flags = 0; } np->cur_rx = 0; np->refill_rx = 0; for (i = 0; i < RX_RING; i++) { rx_ring[i].Flags = 0; } return alloc_rx(nic);}static void set_multicast(struct nic *nic){ u8 *base = (u8 *) BASE; u32 addr[2]; u32 mask[2]; u32 pff; u32 alwaysOff[2]; u32 alwaysOn[2]; memset(addr, 0, sizeof(addr)); memset(mask, 0, sizeof(mask)); pff = NVREG_PFF_MYADDR; alwaysOn[0] = alwaysOn[1] = alwaysOff[0] = alwaysOff[1] = 0; addr[0] = alwaysOn[0]; addr[1] = alwaysOn[1]; mask[0] = alwaysOn[0] | alwaysOff[0]; mask[1] = alwaysOn[1] | alwaysOff[1]; addr[0] |= NVREG_MCASTADDRA_FORCE; pff |= NVREG_PFF_ALWAYS; stop_rx(); writel(addr[0], base + NvRegMulticastAddrA); writel(addr[1], base + NvRegMulticastAddrB); writel(mask[0], base + NvRegMulticastMaskA); writel(mask[1], base + NvRegMulticastMaskB); writel(pff, base + NvRegPacketFilterFlags); start_rx(nic);}/**************************************************************************RESET - Reset the NIC to prepare for use***************************************************************************/static int forcedeth_reset(struct nic *nic){ u8 *base = (u8 *) BASE; int ret, oom, i; ret = 0; dprintf(("forcedeth: open\n")); /* 1) erase previous misconfiguration */ /* 4.1-1: stop adapter: ignored, 4.3 seems to be overkill */ writel(NVREG_MCASTADDRA_FORCE, base + NvRegMulticastAddrA); writel(0, base + NvRegMulticastAddrB); writel(0, base + NvRegMulticastMaskA); writel(0, base + NvRegMulticastMaskB); writel(0, base + NvRegPacketFilterFlags); writel(0, base + NvRegAdapterControl); writel(0, base + NvRegLinkSpeed); writel(0, base + NvRegUnknownTransmitterReg); txrx_reset(nic); writel(0, base + NvRegUnknownSetupReg6); /* 2) initialize descriptor rings */ np->in_shutdown = 0; oom = init_ring(nic); /* 3) set mac address */ { u32 mac[2]; mac[0] = (nic->node_addr[0] << 0) + (nic->node_addr[1] << 8) + (nic->node_addr[2] << 16) + (nic->node_addr[3] << 24); mac[1] = (nic->node_addr[4] << 0) + (nic->node_addr[5] << 8); writel(mac[0], base + NvRegMacAddrA); writel(mac[1], base + NvRegMacAddrB); } /* 4) continue setup */ np->linkspeed = NVREG_LINKSPEED_FORCE | NVREG_LINKSPEED_10; np->duplex = 0; writel(NVREG_UNKSETUP3_VAL1, base + NvRegUnknownSetupReg3); writel(0, base + NvRegTxRxControl); pci_push(base); writel(NVREG_TXRXCTL_BIT1, base + NvRegTxRxControl); reg_delay(NvRegUnknownSetupReg5, NVREG_UNKSETUP5_BIT31, NVREG_UNKSETUP5_BIT31, NV_SETUP5_DELAY, NV_SETUP5_DELAYMAX, "open: SetupReg5, Bit 31 remained off\n"); writel(0, base + NvRegUnknownSetupReg4); /* 5) Find a suitable PHY */ writel(NVREG_MIISPEED_BIT8 | NVREG_MIIDELAY, base + NvRegMIISpeed); for (i = 1; i < 32; i++) { int id1, id2; id1 = mii_rw(nic, i, MII_PHYSID1, MII_READ); if (id1 < 0) continue; id2 = mii_rw(nic, i, MII_PHYSID2, MII_READ); if (id2 < 0) continue; dprintf(("open: Found PHY %04x:%04x at address %d.\n", id1, id2, i)); np->phyaddr = i; update_linkspeed(nic); break; } if (i == 32) { printf("open: failing due to lack of suitable PHY.\n"); ret = -1; goto out_drain; } printf("%d-Mbs Link, %s-Duplex\n", np->linkspeed & NVREG_LINKSPEED_10 ? 10 : 100, np->duplex ? "Full" : "Half"); /* 6) continue setup */ writel(NVREG_MISC1_FORCE | (np->duplex ? 0 : NVREG_MISC1_HD), base + NvRegMisc1); writel(readl(base + NvRegTransmitterStatus), base + NvRegTransmitterStatus); writel(NVREG_PFF_ALWAYS, base + NvRegPacketFilterFlags); writel(NVREG_OFFLOAD_NORMAL, base + NvRegOffloadConfig); writel(readl(base + NvRegReceiverStatus), base + NvRegReceiverStatus); /* FIXME: I cheated and used the calculator to get a random number */ i = 75963081; writel(NVREG_RNDSEED_FORCE | (i & NVREG_RNDSEED_MASK), base + NvRegRandomSeed); writel(NVREG_UNKSETUP1_VAL, base + NvRegUnknownSetupReg1); writel(NVREG_UNKSETUP2_VAL, base + NvRegUnknownSetupReg2); writel(NVREG_POLL_DEFAULT, base + NvRegPollingInterval); writel(NVREG_UNKSETUP6_VAL, base + NvRegUnknownSetupReg6); writel((np-> phyaddr << NVREG_ADAPTCTL_PHYSHIFT) | NVREG_ADAPTCTL_PHYVALID, base + NvRegAdapterControl); writel(NVREG_UNKSETUP4_VAL, base + NvRegUnknownSetupReg4); writel(NVREG_WAKEUPFLAGS_VAL, base + NvRegWakeUpFlags); /* 7) start packet processing */ writel((u32) virt_to_le32desc(&rx_ring[0]), base + NvRegRxRingPhysAddr); writel((u32) virt_to_le32desc(&tx_ring[0]), base + NvRegTxRingPhysAddr); writel(((RX_RING - 1) << NVREG_RINGSZ_RXSHIFT) + ((TX_RING - 1) << NVREG_RINGSZ_TXSHIFT), base + NvRegRingSizes); i = readl(base + NvRegPowerState); if ((i & NVREG_POWERSTATE_POWEREDUP) == 0) { writel(NVREG_POWERSTATE_POWEREDUP | i, base + NvRegPowerState); } pci_push(base); udelay(10); writel(readl(base + NvRegPowerState) | NVREG_POWERSTATE_VALID, base + NvRegPowerState); writel(NVREG_ADAPTCTL_RUNNING, base + NvRegAdapterControl); writel(0, base + NvRegIrqMask); pci_push(base); writel(NVREG_IRQSTAT_MASK, base + NvRegIrqStatus); pci_push(base); writel(NVREG_MIISTAT_MASK2, base + NvRegMIIStatus); writel(NVREG_IRQSTAT_MASK, base + NvRegIrqStatus); pci_push(base);/* writel(np->irqmask, base + NvRegIrqMask);*/ writel(NVREG_MCASTADDRA_FORCE, base + NvRegMulticastAddrA); writel(0, base + NvRegMulticastAddrB); writel(0, base + NvRegMulticastMaskA); writel(0, base + NvRegMulticastMaskB); writel(NVREG_PFF_ALWAYS | NVREG_PFF_MYADDR, base + NvRegPacketFilterFlags); set_multicast(nic); //start_rx(nic); start_tx(nic); if (! (mii_rw(nic, np->phyaddr, MII_BMSR, MII_READ) & BMSR_ANEGCOMPLETE)) { printf("no link during initialization.\n"); } udelay(10000); out_drain: return ret;}//extern void hex_dump(const char *data, const unsigned int len);/**************************************************************************POLL - Wait for a frame***************************************************************************/static int forcedeth_poll(struct nic *nic){ /* return true if there's an ethernet packet ready to read */ /* nic->packet should contain data on return */ /* nic->packetlen should contain length of data */ struct ring_desc *prd; int len; int i; i = np->cur_rx % RX_RING; prd = &rx_ring[i]; if (prd->Flags & cpu_to_le16(NV_RX_DESCRIPTORVALID)) { /* got a valid packet - forward it to the network core */ len = cpu_to_le16(prd->Length); nic->packetlen = len; //hex_dump(rxb + (i * RX_NIC_BUFSIZE), len); memcpy(nic->packet, rxb + (i * RX_NIC_BUFSIZE), nic->packetlen); wmb(); np->cur_rx++; alloc_rx(nic); return 1; } return 0; /* initially as this is called to flush the input */}/**************************************************************************TRANSMIT - Transmit a frame***************************************************************************/static void forcedeth_transmit(struct nic *nic, const char *d, /* Destination */ unsigned int t, /* Type */ unsigned int s, /* size */ const char *p){ /* Packet */ /* send the packet to destination */ u8 *ptxb; u16 nstype; //u16 status; u8 *base = (u8 *) BASE; int nr = np->next_tx % TX_RING; /* point to the current txb incase multiple tx_rings are used */ ptxb = txb + (nr * RX_NIC_BUFSIZE); //np->tx_skbuff[nr] = ptxb; /* copy the packet to ring buffer */ memcpy(ptxb, d, ETH_ALEN); /* dst */ memcpy(ptxb + ETH_ALEN, nic->node_addr, ETH_ALEN); /* src */ nstype = htons((u16) t); /* type */ memcpy(ptxb + 2 * ETH_ALEN, (u8 *) & nstype, 2); /* type */ memcpy(ptxb + ETH_HLEN, p, s); s += ETH_HLEN; while (s < ETH_ZLEN) /* pad to min length */ ptxb[s++] = '\0'; tx_ring[nr].PacketBuffer = (u32) virt_to_le32desc(ptxb); tx_ring[nr].Length = cpu_to_le16(s - 1); wmb(); tx_ring[nr].Flags = np->tx_flags; writel(NVREG_TXRXCTL_KICK, base + NvRegTxRxControl); pci_push(base); tx_ring[nr].Flags = np->tx_flags; np->next_tx++;}/**************************************************************************DISABLE - Turn off ethernet interface***************************************************************************/static void forcedeth_disable(struct dev *dev __unused){ /* put the card in its initial state */ /* This function serves 3 purposes. * This disables DMA and interrupts so we don't receive * unexpected packets or interrupts from the card after * etherboot has finished. * This frees resources so etherboot may use * this driver on another interface * This allows etherboot to reinitialize the interface * if something is something goes wrong. */ u8 *base = (u8 *) BASE; np->in_shutdown = 1; stop_tx(); stop_rx(); /* disable interrupts on the nic or we will lock up */ writel(0, base + NvRegIrqMask); pci_push(base); dprintf(("Irqmask is zero again\n")); /* specia op:o write back the misordered MAC address - otherwise * the next probe_nic would see a wrong address. */ writel(np->orig_mac[0], base + NvRegMacAddrA); writel(np->orig_mac[1], base + NvRegMacAddrB);}/** * is_valid_ether_addr - Determine if the given Ethernet address is valid * @addr: Pointer to a six-byte array containing the Ethernet address * * Check that the Ethernet address (MAC) is not 00:00:00:00:00:00, is not * a multicast address, and is not FF:FF:FF:FF:FF:FF. The multicast * and FF:FF:... tests are combined into the single test "!(addr[0]&1)". * * Return true if the address is valid. */static inline int is_valid_ether_addr( u8 *addr ) { const char zaddr[6] = {0,}; return !(addr[0]&1) && memcmp( addr, zaddr, 6);}/**************************************************************************PROBE - Look for an adapter, this routine's visible to the outside***************************************************************************/#define IORESOURCE_MEM 0x00000200#define board_found 1#define valid_link 0static int forcedeth_probe(struct dev *dev, struct pci_device *pci){ struct nic *nic = (struct nic *) dev; unsigned long addr; int sz; u8 *base; if (pci->ioaddr == 0) return 0; printf("forcedeth.c: Found %s, vendor=0x%hX, device=0x%hX\n", pci->name, pci->vendor, pci->dev_id); /* point to private storage */ np = &npx; adjust_pci_device(pci); addr = pci_bar_start(pci, PCI_BASE_ADDRESS_0); sz = pci_bar_size(pci, PCI_BASE_ADDRESS_0); /* BASE is used throughout to address the card */ BASE = (unsigned long) ioremap(addr, sz); if (!BASE) return 0; //rx_ring[0] = rx_ring; //tx_ring[0] = tx_ring; /* read the mac address */ base = (u8 *) BASE; np->orig_mac[0] = readl(base + NvRegMacAddrA); np->orig_mac[1] = readl(base + NvRegMacAddrB); nic->node_addr[0] = (np->orig_mac[1] >> 8) & 0xff; nic->node_addr[1] = (np->orig_mac[1] >> 0) & 0xff; nic->node_addr[2] = (np->orig_mac[0] >> 24) & 0xff; nic->node_addr[3] = (np->orig_mac[0] >> 16) & 0xff; nic->node_addr[4] = (np->orig_mac[0] >> 8) & 0xff; nic->node_addr[5] = (np->orig_mac[0] >> 0) & 0xff; if (!is_valid_ether_addr(nic->node_addr)) { /* * Bad mac address. At least one bios sets the mac address * to 01:23:45:67:89:ab */ printf("Invalid Mac address detected: %!\n", nic->node_addr); printf("Please complain to your hardware vendor.\n"); return 0; } printf("%s: MAC Address %!, ", pci->name, nic->node_addr); np->tx_flags = cpu_to_le16(NV_TX_LASTPACKET | NV_TX_LASTPACKET1 | NV_TX_VALID); switch (pci->dev_id) { case 0x01C3: // nforce np->irqmask = NVREG_IRQMASK_WANTED_2; np->irqmask |= NVREG_IRQ_TIMER; break; case 0x0066: // nforce2 np->tx_flags |= cpu_to_le16(NV_TX_LASTPACKET1); np->irqmask = NVREG_IRQMASK_WANTED_2; np->irqmask |= NVREG_IRQ_TIMER; break; case 0x00D6: // nforce3 np->tx_flags |= cpu_to_le16(NV_TX_LASTPACKET1); np->irqmask = NVREG_IRQMASK_WANTED_2; np->irqmask |= NVREG_IRQ_TIMER; } dprintf(("%s: forcedeth.c: subsystem: %hX:%hX bound to %s\n", pci->name, pci->vendor, pci->dev_id, pci->name)); forcedeth_reset(nic);// if (board_found && valid_link) /* point to NIC specific routines */ dev->disable = forcedeth_disable; nic->poll = forcedeth_poll; nic->transmit = forcedeth_transmit; return 1;// } /* else */}static struct pci_id forcedeth_nics[] = { PCI_ROM(0x10de, 0x01C3, "nforce", "nForce Ethernet Controller"), PCI_ROM(0x10de, 0x0066, "nforce2", "nForce2 Ethernet Controller"), PCI_ROM(0x10de, 0x00D6, "nforce3", "nForce3 Ethernet Controller"),};static struct pci_driver forcedeth_driver __pci_driver = { .type = NIC_DRIVER, .name = "forcedeth", .probe = forcedeth_probe, .ids = forcedeth_nics, .id_count = sizeof(forcedeth_nics) / sizeof(forcedeth_nics[0]), .class = 0,};
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -