static ssize_t idt_dbgfs_info_read()

in hw/idt/ntb_hw_idt.c [2334:2499]


static ssize_t idt_dbgfs_info_read(struct file *filp, char __user *ubuf,
				   size_t count, loff_t *offp)
{
	struct idt_ntb_dev *ndev = filp->private_data;
	unsigned char idx, pidx, cnt;
	unsigned long irqflags, mdeg;
	ssize_t ret = 0, off = 0;
	enum ntb_speed speed;
	enum ntb_width width;
	char *strbuf;
	size_t size;
	u32 data;

	/* Lets limit the buffer size the way the Intel/AMD drivers do */
	size = min_t(size_t, count, 0x1000U);

	/* Allocate the memory for the buffer */
	strbuf = kmalloc(size, GFP_KERNEL);
	if (strbuf == NULL)
		return -ENOMEM;

	/* Put the data into the string buffer */
	off += scnprintf(strbuf + off, size - off,
		"\n\t\tIDT NTB device Information:\n\n");

	/* General local device configurations */
	off += scnprintf(strbuf + off, size - off,
		"Local Port %hhu, Partition %hhu\n", ndev->port, ndev->part);

	/* Peer ports information */
	off += scnprintf(strbuf + off, size - off, "Peers:\n");
	for (idx = 0; idx < ndev->peer_cnt; idx++) {
		off += scnprintf(strbuf + off, size - off,
			"\t%hhu. Port %hhu, Partition %hhu\n",
			idx, ndev->peers[idx].port, ndev->peers[idx].part);
	}

	/* Links status */
	data = idt_ntb_link_is_up(&ndev->ntb, &speed, &width);
	off += scnprintf(strbuf + off, size - off,
		"NTB link status\t- 0x%08x, ", data);
	off += scnprintf(strbuf + off, size - off, "PCIe Gen %d x%d lanes\n",
		speed, width);

	/* Mapping table entries */
	off += scnprintf(strbuf + off, size - off, "NTB Mapping Table:\n");
	for (idx = 0; idx < IDT_MTBL_ENTRY_CNT; idx++) {
		spin_lock_irqsave(&ndev->mtbl_lock, irqflags);
		idt_nt_write(ndev, IDT_NT_NTMTBLADDR, idx);
		data = idt_nt_read(ndev, IDT_NT_NTMTBLDATA);
		spin_unlock_irqrestore(&ndev->mtbl_lock, irqflags);

		/* Print valid entries only */
		if (data & IDT_NTMTBLDATA_VALID) {
			off += scnprintf(strbuf + off, size - off,
				"\t%hhu. Partition %d, Requester ID 0x%04x\n",
				idx, GET_FIELD(NTMTBLDATA_PART, data),
				GET_FIELD(NTMTBLDATA_REQID, data));
		}
	}
	off += scnprintf(strbuf + off, size - off, "\n");

	/* Outbound memory windows information */
	off += scnprintf(strbuf + off, size - off,
		"Outbound Memory Windows:\n");
	for (idx = 0; idx < ndev->mw_cnt; idx += cnt) {
		data = ndev->mws[idx].type;
		cnt = idt_get_mw_count(data);

		/* Print Memory Window information */
		if (data == IDT_MW_DIR)
			off += scnprintf(strbuf + off, size - off,
				"\t%hhu.\t", idx);
		else
			off += scnprintf(strbuf + off, size - off,
				"\t%hhu-%hhu.\t", idx, idx + cnt - 1);

		off += scnprintf(strbuf + off, size - off, "%s BAR%hhu, ",
			idt_get_mw_name(data), ndev->mws[idx].bar);

		off += scnprintf(strbuf + off, size - off,
			"Address align 0x%08llx, ", ndev->mws[idx].addr_align);

		off += scnprintf(strbuf + off, size - off,
			"Size align 0x%08llx, Size max %llu\n",
			ndev->mws[idx].size_align, ndev->mws[idx].size_max);
	}

	/* Inbound memory windows information */
	for (pidx = 0; pidx < ndev->peer_cnt; pidx++) {
		off += scnprintf(strbuf + off, size - off,
			"Inbound Memory Windows for peer %hhu (Port %hhu):\n",
			pidx, ndev->peers[pidx].port);

		/* Print Memory Windows information */
		for (idx = 0; idx < ndev->peers[pidx].mw_cnt; idx += cnt) {
			data = ndev->peers[pidx].mws[idx].type;
			cnt = idt_get_mw_count(data);

			if (data == IDT_MW_DIR)
				off += scnprintf(strbuf + off, size - off,
					"\t%hhu.\t", idx);
			else
				off += scnprintf(strbuf + off, size - off,
					"\t%hhu-%hhu.\t", idx, idx + cnt - 1);

			off += scnprintf(strbuf + off, size - off,
				"%s BAR%hhu, ", idt_get_mw_name(data),
				ndev->peers[pidx].mws[idx].bar);

			off += scnprintf(strbuf + off, size - off,
				"Address align 0x%08llx, ",
				ndev->peers[pidx].mws[idx].addr_align);

			off += scnprintf(strbuf + off, size - off,
				"Size align 0x%08llx, Size max %llu\n",
				ndev->peers[pidx].mws[idx].size_align,
				ndev->peers[pidx].mws[idx].size_max);
		}
	}
	off += scnprintf(strbuf + off, size - off, "\n");

	/* Doorbell information */
	data = idt_sw_read(ndev, IDT_SW_GDBELLSTS);
	off += scnprintf(strbuf + off, size - off,
		 "Global Doorbell state\t- 0x%08x\n", data);
	data = idt_ntb_db_read(&ndev->ntb);
	off += scnprintf(strbuf + off, size - off,
		 "Local  Doorbell state\t- 0x%08x\n", data);
	data = idt_nt_read(ndev, IDT_NT_INDBELLMSK);
	off += scnprintf(strbuf + off, size - off,
		 "Local  Doorbell mask\t- 0x%08x\n", data);
	off += scnprintf(strbuf + off, size - off, "\n");

	/* Messaging information */
	off += scnprintf(strbuf + off, size - off,
		 "Message event valid\t- 0x%08x\n", IDT_MSG_MASK);
	data = idt_ntb_msg_read_sts(&ndev->ntb);
	off += scnprintf(strbuf + off, size - off,
		 "Message event status\t- 0x%08x\n", data);
	data = idt_nt_read(ndev, IDT_NT_MSGSTSMSK);
	off += scnprintf(strbuf + off, size - off,
		 "Message event mask\t- 0x%08x\n", data);
	off += scnprintf(strbuf + off, size - off,
		 "Message data:\n");
	for (idx = 0; idx < IDT_MSG_CNT; idx++) {
		int src;
		data = idt_ntb_msg_read(&ndev->ntb, &src, idx);
		off += scnprintf(strbuf + off, size - off,
			"\t%hhu. 0x%08x from peer %hhu (Port %hhu)\n",
			idx, data, src, ndev->peers[src].port);
	}
	off += scnprintf(strbuf + off, size - off, "\n");

	/* Current temperature */
	idt_read_temp(ndev, IDT_TEMP_CUR, &mdeg);
	off += scnprintf(strbuf + off, size - off,
		"Switch temperature\t\t- %hhd.%hhuC\n",
		idt_get_deg(mdeg), idt_get_deg_frac(mdeg));

	/* Copy the buffer to the User Space */
	ret = simple_read_from_buffer(ubuf, count, offp, strbuf, off);
	kfree(strbuf);

	return ret;
}