📄 spider_net.c
字号:
return 0;}/** * spider_net_init_firmware - reads in firmware parts * @card: card structure * * Returns 0 on success, <0 on failure * * spider_net_init_firmware opens the sequencer firmware and does some basic * checks. This function opens and releases the firmware structure. A call * to download the firmware is performed before the release. * * Firmware format * =============== * spider_fw.bin is expected to be a file containing 6*1024*4 bytes, 4k being * the program for each sequencer. Use the command * tail -q -n +2 Seq_code1_0x088.txt Seq_code2_0x090.txt \ * Seq_code3_0x098.txt Seq_code4_0x0A0.txt Seq_code5_0x0A8.txt \ * Seq_code6_0x0B0.txt | xxd -r -p -c4 > spider_fw.bin * * to generate spider_fw.bin, if you have sequencer programs with something * like the following contents for each sequencer: * <ONE LINE COMMENT> * <FIRST 4-BYTES-WORD FOR SEQUENCER> * <SECOND 4-BYTES-WORD FOR SEQUENCER> * ... * <1024th 4-BYTES-WORD FOR SEQUENCER> */static intspider_net_init_firmware(struct spider_net_card *card){ struct firmware *firmware = NULL; struct device_node *dn; const u8 *fw_prop = NULL; int err = -ENOENT; int fw_size; if (request_firmware((const struct firmware **)&firmware, SPIDER_NET_FIRMWARE_NAME, &card->pdev->dev) == 0) { if ( (firmware->size != SPIDER_NET_FIRMWARE_LEN) && netif_msg_probe(card) ) { dev_err(&card->netdev->dev, "Incorrect size of spidernet firmware in " \ "filesystem. Looking in host firmware...\n"); goto try_host_fw; } err = spider_net_download_firmware(card, firmware->data); release_firmware(firmware); if (err) goto try_host_fw; goto done; }try_host_fw: dn = pci_device_to_OF_node(card->pdev); if (!dn) goto out_err; fw_prop = of_get_property(dn, "firmware", &fw_size); if (!fw_prop) goto out_err; if ( (fw_size != SPIDER_NET_FIRMWARE_LEN) && netif_msg_probe(card) ) { dev_err(&card->netdev->dev, "Incorrect size of spidernet firmware in host firmware\n"); goto done; } err = spider_net_download_firmware(card, fw_prop);done: return err;out_err: if (netif_msg_probe(card)) dev_err(&card->netdev->dev, "Couldn't find spidernet firmware in filesystem " \ "or host firmware\n"); return err;}/** * spider_net_open - called upon ifonfig up * @netdev: interface device structure * * returns 0 on success, <0 on failure * * spider_net_open allocates all the descriptors and memory needed for * operation, sets up multicast list and enables interrupts */intspider_net_open(struct net_device *netdev){ struct spider_net_card *card = netdev_priv(netdev); int result; result = spider_net_init_firmware(card); if (result) goto init_firmware_failed; /* start probing with copper */ spider_net_setup_aneg(card); if (card->phy.def->phy_id) mod_timer(&card->aneg_timer, jiffies + SPIDER_NET_ANEG_TIMER); result = spider_net_init_chain(card, &card->tx_chain); if (result) goto alloc_tx_failed; card->low_watermark = NULL; result = spider_net_init_chain(card, &card->rx_chain); if (result) goto alloc_rx_failed; /* Allocate rx skbs */ if (spider_net_alloc_rx_skbs(card)) goto alloc_skbs_failed; spider_net_set_multi(netdev); /* further enhancement: setup hw vlan, if needed */ result = -EBUSY; if (request_irq(netdev->irq, spider_net_interrupt, IRQF_SHARED, netdev->name, netdev)) goto register_int_failed; spider_net_enable_card(card); netif_start_queue(netdev); netif_carrier_on(netdev); napi_enable(&card->napi); spider_net_enable_interrupts(card); return 0;register_int_failed: spider_net_free_rx_chain_contents(card);alloc_skbs_failed: spider_net_free_chain(card, &card->rx_chain);alloc_rx_failed: spider_net_free_chain(card, &card->tx_chain);alloc_tx_failed: del_timer_sync(&card->aneg_timer);init_firmware_failed: return result;}/** * spider_net_link_phy * @data: used for pointer to card structure * */static void spider_net_link_phy(unsigned long data){ struct spider_net_card *card = (struct spider_net_card *)data; struct mii_phy *phy = &card->phy; /* if link didn't come up after SPIDER_NET_ANEG_TIMEOUT tries, setup phy again */ if (card->aneg_count > SPIDER_NET_ANEG_TIMEOUT) { pr_info("%s: link is down trying to bring it up\n", card->netdev->name); switch (card->medium) { case BCM54XX_COPPER: /* enable fiber with autonegotiation first */ if (phy->def->ops->enable_fiber) phy->def->ops->enable_fiber(phy, 1); card->medium = BCM54XX_FIBER; break; case BCM54XX_FIBER: /* fiber didn't come up, try to disable fiber autoneg */ if (phy->def->ops->enable_fiber) phy->def->ops->enable_fiber(phy, 0); card->medium = BCM54XX_UNKNOWN; break; case BCM54XX_UNKNOWN: /* copper, fiber with and without failed, * retry from beginning */ spider_net_setup_aneg(card); card->medium = BCM54XX_COPPER; break; } card->aneg_count = 0; mod_timer(&card->aneg_timer, jiffies + SPIDER_NET_ANEG_TIMER); return; } /* link still not up, try again later */ if (!(phy->def->ops->poll_link(phy))) { card->aneg_count++; mod_timer(&card->aneg_timer, jiffies + SPIDER_NET_ANEG_TIMER); return; } /* link came up, get abilities */ phy->def->ops->read_link(phy); spider_net_write_reg(card, SPIDER_NET_GMACST, spider_net_read_reg(card, SPIDER_NET_GMACST)); spider_net_write_reg(card, SPIDER_NET_GMACINTEN, 0x4); if (phy->speed == 1000) spider_net_write_reg(card, SPIDER_NET_GMACMODE, 0x00000001); else spider_net_write_reg(card, SPIDER_NET_GMACMODE, 0); card->aneg_count = 0; pr_debug("Found %s with %i Mbps, %s-duplex %sautoneg.\n", phy->def->name, phy->speed, phy->duplex==1 ? "Full" : "Half", phy->autoneg==1 ? "" : "no "); return;}/** * spider_net_setup_phy - setup PHY * @card: card structure * * returns 0 on success, <0 on failure * * spider_net_setup_phy is used as part of spider_net_probe. **/static intspider_net_setup_phy(struct spider_net_card *card){ struct mii_phy *phy = &card->phy; spider_net_write_reg(card, SPIDER_NET_GDTDMASEL, SPIDER_NET_DMASEL_VALUE); spider_net_write_reg(card, SPIDER_NET_GPCCTRL, SPIDER_NET_PHY_CTRL_VALUE); phy->dev = card->netdev; phy->mdio_read = spider_net_read_phy; phy->mdio_write = spider_net_write_phy; for (phy->mii_id = 1; phy->mii_id <= 31; phy->mii_id++) { unsigned short id; id = spider_net_read_phy(card->netdev, phy->mii_id, MII_BMSR); if (id != 0x0000 && id != 0xffff) { if (!mii_phy_probe(phy, phy->mii_id)) { pr_info("Found %s.\n", phy->def->name); break; } } } return 0;}/** * spider_net_workaround_rxramfull - work around firmware bug * @card: card structure * * no return value **/static voidspider_net_workaround_rxramfull(struct spider_net_card *card){ int i, sequencer = 0; /* cancel reset */ spider_net_write_reg(card, SPIDER_NET_CKRCTRL, SPIDER_NET_CKRCTRL_RUN_VALUE); /* empty sequencer data */ for (sequencer = 0; sequencer < SPIDER_NET_FIRMWARE_SEQS; sequencer++) { spider_net_write_reg(card, SPIDER_NET_GSnPRGADR + sequencer * 8, 0x0); for (i = 0; i < SPIDER_NET_FIRMWARE_SEQWORDS; i++) { spider_net_write_reg(card, SPIDER_NET_GSnPRGDAT + sequencer * 8, 0x0); } } /* set sequencer operation */ spider_net_write_reg(card, SPIDER_NET_GSINIT, 0x000000fe); /* reset */ spider_net_write_reg(card, SPIDER_NET_CKRCTRL, SPIDER_NET_CKRCTRL_STOP_VALUE);}/** * spider_net_stop - called upon ifconfig down * @netdev: interface device structure * * always returns 0 */intspider_net_stop(struct net_device *netdev){ struct spider_net_card *card = netdev_priv(netdev); napi_disable(&card->napi); netif_carrier_off(netdev); netif_stop_queue(netdev); del_timer_sync(&card->tx_timer); del_timer_sync(&card->aneg_timer); spider_net_disable_interrupts(card); free_irq(netdev->irq, netdev); spider_net_write_reg(card, SPIDER_NET_GDTDMACCNTR, SPIDER_NET_DMA_TX_FEND_VALUE); /* turn off DMA, force end */ spider_net_disable_rxdmac(card); /* release chains */ spider_net_release_tx_chain(card, 1); spider_net_free_rx_chain_contents(card); spider_net_free_chain(card, &card->tx_chain); spider_net_free_chain(card, &card->rx_chain); return 0;}/** * spider_net_tx_timeout_task - task scheduled by the watchdog timeout * function (to be called not under interrupt status) * @data: data, is interface device structure * * called as task when tx hangs, resets interface (if interface is up) */static voidspider_net_tx_timeout_task(struct work_struct *work){ struct spider_net_card *card = container_of(work, struct spider_net_card, tx_timeout_task); struct net_device *netdev = card->netdev; if (!(netdev->flags & IFF_UP)) goto out; netif_device_detach(netdev); spider_net_stop(netdev); spider_net_workaround_rxramfull(card); spider_net_init_card(card); if (spider_net_setup_phy(card)) goto out; spider_net_open(netdev); spider_net_kick_tx_dma(card); netif_device_attach(netdev);out: atomic_dec(&card->tx_timeout_task_counter);}/** * spider_net_tx_timeout - called when the tx timeout watchdog kicks in. * @netdev: interface device structure * * called, if tx hangs. Schedules a task that resets the interface */static voidspider_net_tx_timeout(struct net_device *netdev){ struct spider_net_card *card; card = netdev_priv(netdev); atomic_inc(&card->tx_timeout_task_counter); if (netdev->flags & IFF_UP) schedule_work(&card->tx_timeout_task); else atomic_dec(&card->tx_timeout_task_counter); card->spider_stats.tx_timeouts++;}/** * spider_net_setup_netdev_ops - initialization of net_device operations * @netdev: net_device structure * * fills out function pointers in the net_device structure */static voidspider_net_setup_netdev_ops(struct net_device *netdev){ netdev->open = &spider_net_open; netdev->stop = &spider_net_stop; netdev->hard_start_xmit = &spider_net_xmit; netdev->set_multicast_list = &spider_net_set_multi; netdev->set_mac_address = &spider_net_set_mac; netdev->change_mtu = &spider_net_change_mtu; netdev->do_ioctl = &spider_net_do_ioctl; /* tx watchdog */ netdev->tx_timeout = &spider_net_tx_timeout; netdev->watchdog_timeo = SPIDER_NET_WATCHDOG_TIMEOUT; /* HW VLAN */#ifdef CONFIG_NET_POLL_CONTROLLER /* poll controller */ netdev->poll_controller = &spider_net_poll_controller;#endif /* CONFIG_NET_POLL_CONTROLLER */ /* ethtool ops */ netdev->ethtool_ops = &spider_net_ethtool_ops;}/** * spider_net_setup_netdev - initialization of net_device * @card: card structure * * Returns 0 on success or <0 on failure * * spider_net_setup_netdev initializes the net_device structure **/static intspider_net_setup_netdev(struct spider_net_card *card){ int result; struct net_device *netdev = card->netdev; struct device_node *dn; struct sockaddr addr; const u8 *mac; SET_NETDEV_DEV(netdev, &card->pdev->dev); pci_set_drvdata(card->pdev, netdev); init_timer(&card->tx_timer); card->tx_timer.function = (void (*)(unsigned long)) spider_net_cleanup_tx_ring; card->tx_timer.data = (unsigned long) card; netdev->irq = card->pdev->irq; card->aneg_count = 0; init_timer(&card->aneg_timer); card->aneg_timer.function = spider_net_link_phy; card->aneg_timer.data = (unsigned long) card; card->options.rx_csum = SPIDER_NET_RX_CSUM_DEFAULT; netif_napi_add(netdev, &card->napi, spider_net_poll, SPIDER_NET_NAPI_WEIGHT); spider_net_setup_netdev_ops(netdev); netdev->features = NETIF_F_IP_CSUM | NETIF_F_LLTX; /* some time: NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX | * NETIF_F_HW_VLAN_FILTER */ netdev->irq = card->pdev->irq; card->num_rx_ints = 0; card->ignore_rx_ramfull = 0; dn = pci_device_to_OF_node(card->pdev); if (!dn) return -EIO; mac = of_get_property(dn, "local-mac-address", NULL); if (!mac) return -EIO; memcpy(addr.sa_data, mac, ETH_ALEN); result =
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -