⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 myri10ge.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
	 * response in the confirmation address.  The firmware should	 * write a -1 there to indicate it is alive and well	 */	dma_low = MYRI10GE_LOWPART_TO_U32(mgp->cmd_bus);	dma_high = MYRI10GE_HIGHPART_TO_U32(mgp->cmd_bus);	buf[0] = htonl(dma_high);	/* confirm addr MSW */	buf[1] = htonl(dma_low);	/* confirm addr LSW */	buf[2] = MYRI10GE_NO_CONFIRM_DATA;	/* confirm data */	buf[3] = htonl(dma_high);	/* dummy addr MSW */	buf[4] = htonl(dma_low);	/* dummy addr LSW */	buf[5] = htonl(enable);	/* enable? */	submit = mgp->sram + MXGEFW_BOOT_DUMMY_RDMA;	myri10ge_pio_copy(submit, &buf, sizeof(buf));	for (i = 0; mgp->cmd->data != MYRI10GE_NO_CONFIRM_DATA && i < 20; i++)		msleep(1);	if (mgp->cmd->data != MYRI10GE_NO_CONFIRM_DATA)		dev_err(&mgp->pdev->dev, "dummy rdma %s failed\n",			(enable ? "enable" : "disable"));}static intmyri10ge_validate_firmware(struct myri10ge_priv *mgp,			   struct mcp_gen_header *hdr){	struct device *dev = &mgp->pdev->dev;	/* check firmware type */	if (ntohl(hdr->mcp_type) != MCP_TYPE_ETH) {		dev_err(dev, "Bad firmware type: 0x%x\n", ntohl(hdr->mcp_type));		return -EINVAL;	}	/* save firmware version for ethtool */	strncpy(mgp->fw_version, hdr->version, sizeof(mgp->fw_version));	sscanf(mgp->fw_version, "%d.%d.%d", &mgp->fw_ver_major,	       &mgp->fw_ver_minor, &mgp->fw_ver_tiny);	if (!(mgp->fw_ver_major == MXGEFW_VERSION_MAJOR	      && mgp->fw_ver_minor == MXGEFW_VERSION_MINOR)) {		dev_err(dev, "Found firmware version %s\n", mgp->fw_version);		dev_err(dev, "Driver needs %d.%d\n", MXGEFW_VERSION_MAJOR,			MXGEFW_VERSION_MINOR);		return -EINVAL;	}	return 0;}static int myri10ge_load_hotplug_firmware(struct myri10ge_priv *mgp, u32 * size){	unsigned crc, reread_crc;	const struct firmware *fw;	struct device *dev = &mgp->pdev->dev;	struct mcp_gen_header *hdr;	size_t hdr_offset;	int status;	unsigned i;	if ((status = request_firmware(&fw, mgp->fw_name, dev)) < 0) {		dev_err(dev, "Unable to load %s firmware image via hotplug\n",			mgp->fw_name);		status = -EINVAL;		goto abort_with_nothing;	}	/* check size */	if (fw->size >= mgp->sram_size - MYRI10GE_FW_OFFSET ||	    fw->size < MCP_HEADER_PTR_OFFSET + 4) {		dev_err(dev, "Firmware size invalid:%d\n", (int)fw->size);		status = -EINVAL;		goto abort_with_fw;	}	/* check id */	hdr_offset = ntohl(*(__be32 *) (fw->data + MCP_HEADER_PTR_OFFSET));	if ((hdr_offset & 3) || hdr_offset + sizeof(*hdr) > fw->size) {		dev_err(dev, "Bad firmware file\n");		status = -EINVAL;		goto abort_with_fw;	}	hdr = (void *)(fw->data + hdr_offset);	status = myri10ge_validate_firmware(mgp, hdr);	if (status != 0)		goto abort_with_fw;	crc = crc32(~0, fw->data, fw->size);	for (i = 0; i < fw->size; i += 256) {		myri10ge_pio_copy(mgp->sram + MYRI10GE_FW_OFFSET + i,				  fw->data + i,				  min(256U, (unsigned)(fw->size - i)));		mb();		readb(mgp->sram);	}	/* corruption checking is good for parity recovery and buggy chipset */	memcpy_fromio(fw->data, mgp->sram + MYRI10GE_FW_OFFSET, fw->size);	reread_crc = crc32(~0, fw->data, fw->size);	if (crc != reread_crc) {		dev_err(dev, "CRC failed(fw-len=%u), got 0x%x (expect 0x%x)\n",			(unsigned)fw->size, reread_crc, crc);		status = -EIO;		goto abort_with_fw;	}	*size = (u32) fw->size;abort_with_fw:	release_firmware(fw);abort_with_nothing:	return status;}static int myri10ge_adopt_running_firmware(struct myri10ge_priv *mgp){	struct mcp_gen_header *hdr;	struct device *dev = &mgp->pdev->dev;	const size_t bytes = sizeof(struct mcp_gen_header);	size_t hdr_offset;	int status;	/* find running firmware header */	hdr_offset = ntohl(__raw_readl(mgp->sram + MCP_HEADER_PTR_OFFSET));	if ((hdr_offset & 3) || hdr_offset + sizeof(*hdr) > mgp->sram_size) {		dev_err(dev, "Running firmware has bad header offset (%d)\n",			(int)hdr_offset);		return -EIO;	}	/* copy header of running firmware from SRAM to host memory to	 * validate firmware */	hdr = kmalloc(bytes, GFP_KERNEL);	if (hdr == NULL) {		dev_err(dev, "could not malloc firmware hdr\n");		return -ENOMEM;	}	memcpy_fromio(hdr, mgp->sram + hdr_offset, bytes);	status = myri10ge_validate_firmware(mgp, hdr);	kfree(hdr);	/* check to see if adopted firmware has bug where adopting	 * it will cause broadcasts to be filtered unless the NIC	 * is kept in ALLMULTI mode */	if (mgp->fw_ver_major == 1 && mgp->fw_ver_minor == 4 &&	    mgp->fw_ver_tiny >= 4 && mgp->fw_ver_tiny <= 11) {		mgp->adopted_rx_filter_bug = 1;		dev_warn(dev, "Adopting fw %d.%d.%d: "			 "working around rx filter bug\n",			 mgp->fw_ver_major, mgp->fw_ver_minor,			 mgp->fw_ver_tiny);	}	return status;}static int myri10ge_load_firmware(struct myri10ge_priv *mgp){	char __iomem *submit;	__be32 buf[16];	u32 dma_low, dma_high, size;	int status, i;	struct myri10ge_cmd cmd;	size = 0;	status = myri10ge_load_hotplug_firmware(mgp, &size);	if (status) {		dev_warn(&mgp->pdev->dev, "hotplug firmware loading failed\n");		/* Do not attempt to adopt firmware if there		 * was a bad crc */		if (status == -EIO)			return status;		status = myri10ge_adopt_running_firmware(mgp);		if (status != 0) {			dev_err(&mgp->pdev->dev,				"failed to adopt running firmware\n");			return status;		}		dev_info(&mgp->pdev->dev,			 "Successfully adopted running firmware\n");		if (mgp->tx.boundary == 4096) {			dev_warn(&mgp->pdev->dev,				 "Using firmware currently running on NIC"				 ".  For optimal\n");			dev_warn(&mgp->pdev->dev,				 "performance consider loading optimized "				 "firmware\n");			dev_warn(&mgp->pdev->dev, "via hotplug\n");		}		mgp->fw_name = "adopted";		mgp->tx.boundary = 2048;		return status;	}	/* clear confirmation addr */	mgp->cmd->data = 0;	mb();	/* send a reload command to the bootstrap MCP, and wait for the	 *  response in the confirmation address.  The firmware should	 * write a -1 there to indicate it is alive and well	 */	dma_low = MYRI10GE_LOWPART_TO_U32(mgp->cmd_bus);	dma_high = MYRI10GE_HIGHPART_TO_U32(mgp->cmd_bus);	buf[0] = htonl(dma_high);	/* confirm addr MSW */	buf[1] = htonl(dma_low);	/* confirm addr LSW */	buf[2] = MYRI10GE_NO_CONFIRM_DATA;	/* confirm data */	/* FIX: All newest firmware should un-protect the bottom of	 * the sram before handoff. However, the very first interfaces	 * do not. Therefore the handoff copy must skip the first 8 bytes	 */	buf[3] = htonl(MYRI10GE_FW_OFFSET + 8);	/* where the code starts */	buf[4] = htonl(size - 8);	/* length of code */	buf[5] = htonl(8);	/* where to copy to */	buf[6] = htonl(0);	/* where to jump to */	submit = mgp->sram + MXGEFW_BOOT_HANDOFF;	myri10ge_pio_copy(submit, &buf, sizeof(buf));	mb();	msleep(1);	mb();	i = 0;	while (mgp->cmd->data != MYRI10GE_NO_CONFIRM_DATA && i < 20) {		msleep(1);		i++;	}	if (mgp->cmd->data != MYRI10GE_NO_CONFIRM_DATA) {		dev_err(&mgp->pdev->dev, "handoff failed\n");		return -ENXIO;	}	dev_info(&mgp->pdev->dev, "handoff confirmed\n");	myri10ge_dummy_rdma(mgp, 1);	/* probe for IPv6 TSO support */	mgp->features = NETIF_F_SG | NETIF_F_HW_CSUM | NETIF_F_TSO;	status = myri10ge_send_cmd(mgp, MXGEFW_CMD_GET_MAX_TSO6_HDR_SIZE,				   &cmd, 0);	if (status == 0) {		mgp->max_tso6 = cmd.data0;		mgp->features |= NETIF_F_TSO6;	}	return 0;}static int myri10ge_update_mac_address(struct myri10ge_priv *mgp, u8 * addr){	struct myri10ge_cmd cmd;	int status;	cmd.data0 = ((addr[0] << 24) | (addr[1] << 16)		     | (addr[2] << 8) | addr[3]);	cmd.data1 = ((addr[4] << 8) | (addr[5]));	status = myri10ge_send_cmd(mgp, MXGEFW_SET_MAC_ADDRESS, &cmd, 0);	return status;}static int myri10ge_change_pause(struct myri10ge_priv *mgp, int pause){	struct myri10ge_cmd cmd;	int status, ctl;	ctl = pause ? MXGEFW_ENABLE_FLOW_CONTROL : MXGEFW_DISABLE_FLOW_CONTROL;	status = myri10ge_send_cmd(mgp, ctl, &cmd, 0);	if (status) {		printk(KERN_ERR		       "myri10ge: %s: Failed to set flow control mode\n",		       mgp->dev->name);		return status;	}	mgp->pause = pause;	return 0;}static voidmyri10ge_change_promisc(struct myri10ge_priv *mgp, int promisc, int atomic){	struct myri10ge_cmd cmd;	int status, ctl;	ctl = promisc ? MXGEFW_ENABLE_PROMISC : MXGEFW_DISABLE_PROMISC;	status = myri10ge_send_cmd(mgp, ctl, &cmd, atomic);	if (status)		printk(KERN_ERR "myri10ge: %s: Failed to set promisc mode\n",		       mgp->dev->name);}static int myri10ge_dma_test(struct myri10ge_priv *mgp, int test_type){	struct myri10ge_cmd cmd;	int status;	u32 len;	struct page *dmatest_page;	dma_addr_t dmatest_bus;	char *test = " ";	dmatest_page = alloc_page(GFP_KERNEL);	if (!dmatest_page)		return -ENOMEM;	dmatest_bus = pci_map_page(mgp->pdev, dmatest_page, 0, PAGE_SIZE,				   DMA_BIDIRECTIONAL);	/* Run a small DMA test.	 * The magic multipliers to the length tell the firmware	 * to do DMA read, write, or read+write tests.  The	 * results are returned in cmd.data0.  The upper 16	 * bits or the return is the number of transfers completed.	 * The lower 16 bits is the time in 0.5us ticks that the	 * transfers took to complete.	 */	len = mgp->tx.boundary;	cmd.data0 = MYRI10GE_LOWPART_TO_U32(dmatest_bus);	cmd.data1 = MYRI10GE_HIGHPART_TO_U32(dmatest_bus);	cmd.data2 = len * 0x10000;	status = myri10ge_send_cmd(mgp, test_type, &cmd, 0);	if (status != 0) {		test = "read";		goto abort;	}	mgp->read_dma = ((cmd.data0 >> 16) * len * 2) / (cmd.data0 & 0xffff);	cmd.data0 = MYRI10GE_LOWPART_TO_U32(dmatest_bus);	cmd.data1 = MYRI10GE_HIGHPART_TO_U32(dmatest_bus);	cmd.data2 = len * 0x1;	status = myri10ge_send_cmd(mgp, test_type, &cmd, 0);	if (status != 0) {		test = "write";		goto abort;	}	mgp->write_dma = ((cmd.data0 >> 16) * len * 2) / (cmd.data0 & 0xffff);	cmd.data0 = MYRI10GE_LOWPART_TO_U32(dmatest_bus);	cmd.data1 = MYRI10GE_HIGHPART_TO_U32(dmatest_bus);	cmd.data2 = len * 0x10001;	status = myri10ge_send_cmd(mgp, test_type, &cmd, 0);	if (status != 0) {		test = "read/write";		goto abort;	}	mgp->read_write_dma = ((cmd.data0 >> 16) * len * 2 * 2) /	    (cmd.data0 & 0xffff);abort:	pci_unmap_page(mgp->pdev, dmatest_bus, PAGE_SIZE, DMA_BIDIRECTIONAL);	put_page(dmatest_page);	if (status != 0 && test_type != MXGEFW_CMD_UNALIGNED_TEST)		dev_warn(&mgp->pdev->dev, "DMA %s benchmark failed: %d\n",			 test, status);	return status;}static int myri10ge_reset(struct myri10ge_priv *mgp){	struct myri10ge_cmd cmd;	int status;	size_t bytes;	/* try to send a reset command to the card to see if it	 * is alive */	memset(&cmd, 0, sizeof(cmd));	status = myri10ge_send_cmd(mgp, MXGEFW_CMD_RESET, &cmd, 0);	if (status != 0) {		dev_err(&mgp->pdev->dev, "failed reset\n");		return -ENXIO;	}	(void)myri10ge_dma_test(mgp, MXGEFW_DMA_TEST);	/* Now exchange information about interrupts  */	bytes = myri10ge_max_intr_slots * sizeof(*mgp->rx_done.entry);	memset(mgp->rx_done.entry, 0, bytes);	cmd.data0 = (u32) bytes;	status = myri10ge_send_cmd(mgp, MXGEFW_CMD_SET_INTRQ_SIZE, &cmd, 0);	cmd.data0 = MYRI10GE_LOWPART_TO_U32(mgp->rx_done.bus);	cmd.data1 = MYRI10GE_HIGHPART_TO_U32(mgp->rx_done.bus);	status |= myri10ge_send_cmd(mgp, MXGEFW_CMD_SET_INTRQ_DMA, &cmd, 0);	status |=	    myri10ge_send_cmd(mgp, MXGEFW_CMD_GET_IRQ_ACK_OFFSET, &cmd, 0);	mgp->irq_claim = (__iomem __be32 *) (mgp->sram + cmd.data0);	status |= myri10ge_send_cmd(mgp, MXGEFW_CMD_GET_IRQ_DEASSERT_OFFSET,				    &cmd, 0);	mgp->irq_deassert = (__iomem __be32 *) (mgp->sram + cmd.data0);	status |= myri10ge_send_cmd	    (mgp, MXGEFW_CMD_GET_INTR_COAL_DELAY_OFFSET, &cmd, 0);	mgp->intr_coal_delay_ptr = (__iomem __be32 *) (mgp->sram + cmd.data0);	if (status != 0) {		dev_err(&mgp->pdev->dev, "failed set interrupt parameters\n");		return status;	}	put_be32(htonl(mgp->intr_coal_delay), mgp->intr_coal_delay_ptr);	memset(mgp->rx_done.entry, 0, bytes);	/* reset mcp/driver shared state back to 0 */	mgp->tx.req = 0;	mgp->tx.done = 0;	mgp->tx.pkt_start = 0;	mgp->tx.pkt_done = 0;	mgp->rx_big.cnt = 0;	mgp->rx_small.cnt = 0;	mgp->rx_done.idx = 0;	mgp->rx_done.cnt = 0;	mgp->link_changes = 0;	status = myri10ge_update_mac_address(mgp, mgp->dev->dev_addr);	myri10ge_change_pause(mgp, mgp->pause);	myri10ge_set_multicast_list(mgp->dev);	return status;}static inline voidmyri10ge_submit_8rx(struct mcp_kreq_ether_recv __iomem * dst,		    struct mcp_kreq_ether_recv *src){	__be32 low;	low = src->addr_low;	src->addr_low = htonl(DMA_32BIT_MASK);	myri10ge_pio_copy(dst, src, 4 * sizeof(*src));	mb();	myri10ge_pio_copy(dst + 4, src + 4, 4 * sizeof(*src));	mb();	src->addr_low = low;	put_be32(low, &dst->addr_low);	mb();}static inline void myri10ge_vlan_ip_csum(struct sk_buff *skb, __wsum hw_csum){	struct vlan_hdr *vh = (struct vlan_hdr *)(skb->data);	if ((skb->protocol == htons(ETH_P_8021Q)) &&	    (vh->h_vlan_encapsulated_proto == htons(ETH_P_IP) ||	     vh->h_vlan_encapsulated_proto == htons(ETH_P_IPV6))) {		skb->csum = hw_csum;		skb->ip_summed = CHECKSUM_COMPLETE;	}}

⌨️ 快捷键说明

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