brintos

brintos / linux-shallow public Read only

0
0
Text · 17.3 KiB · a6d4c8f Raw
764 lines · c
1// SPDX-License-Identifier: GPL-2.02 3#include <linux/device.h>4#include <linux/err.h>5#include <linux/errno.h>6#include <linux/fs.h>7#include <linux/fsi-sbefifo.h>8#include <linux/gfp.h>9#include <linux/idr.h>10#include <linux/kernel.h>11#include <linux/list.h>12#include <linux/miscdevice.h>13#include <linux/mm.h>14#include <linux/module.h>15#include <linux/mutex.h>16#include <linux/fsi-occ.h>17#include <linux/of.h>18#include <linux/of_platform.h>19#include <linux/platform_device.h>20#include <linux/sched.h>21#include <linux/slab.h>22#include <linux/uaccess.h>23#include <linux/unaligned.h>24 25#define OCC_SRAM_BYTES		409626#define OCC_CMD_DATA_BYTES	409027#define OCC_RESP_DATA_BYTES	408928 29#define OCC_P9_SRAM_CMD_ADDR	0xFFFBE00030#define OCC_P9_SRAM_RSP_ADDR	0xFFFBF00031 32#define OCC_P10_SRAM_CMD_ADDR	0xFFFFD00033#define OCC_P10_SRAM_RSP_ADDR	0xFFFFE00034 35#define OCC_P10_SRAM_MODE	0x58	/* Normal mode, OCB channel 2 */36 37#define OCC_TIMEOUT_MS		100038#define OCC_CMD_IN_PRG_WAIT_MS	5039 40enum versions { occ_p9, occ_p10 };41 42struct occ {43	struct device *dev;44	struct device *sbefifo;45	char name[32];46	int idx;47	bool platform_hwmon;48	u8 sequence_number;49	void *buffer;50	void *client_buffer;51	size_t client_buffer_size;52	size_t client_response_size;53	enum versions version;54	struct miscdevice mdev;55	struct mutex occ_lock;56};57 58#define to_occ(x)	container_of((x), struct occ, mdev)59 60struct occ_response {61	u8 seq_no;62	u8 cmd_type;63	u8 return_status;64	__be16 data_length;65	u8 data[OCC_RESP_DATA_BYTES + 2];	/* two bytes checksum */66} __packed;67 68struct occ_client {69	struct occ *occ;70	struct mutex lock;71	size_t data_size;72	size_t read_offset;73	u8 *buffer;74};75 76#define to_client(x)	container_of((x), struct occ_client, xfr)77 78static DEFINE_IDA(occ_ida);79 80static int occ_open(struct inode *inode, struct file *file)81{82	struct occ_client *client = kzalloc(sizeof(*client), GFP_KERNEL);83	struct miscdevice *mdev = file->private_data;84	struct occ *occ = to_occ(mdev);85 86	if (!client)87		return -ENOMEM;88 89	client->buffer = (u8 *)__get_free_page(GFP_KERNEL);90	if (!client->buffer) {91		kfree(client);92		return -ENOMEM;93	}94 95	client->occ = occ;96	mutex_init(&client->lock);97	file->private_data = client;98	get_device(occ->dev);99 100	/* We allocate a 1-page buffer, make sure it all fits */101	BUILD_BUG_ON((OCC_CMD_DATA_BYTES + 3) > PAGE_SIZE);102	BUILD_BUG_ON((OCC_RESP_DATA_BYTES + 7) > PAGE_SIZE);103 104	return 0;105}106 107static ssize_t occ_read(struct file *file, char __user *buf, size_t len,108			loff_t *offset)109{110	struct occ_client *client = file->private_data;111	ssize_t rc = 0;112 113	if (!client)114		return -ENODEV;115 116	if (len > OCC_SRAM_BYTES)117		return -EINVAL;118 119	mutex_lock(&client->lock);120 121	/* This should not be possible ... */122	if (WARN_ON_ONCE(client->read_offset > client->data_size)) {123		rc = -EIO;124		goto done;125	}126 127	/* Grab how much data we have to read */128	rc = min(len, client->data_size - client->read_offset);129	if (copy_to_user(buf, client->buffer + client->read_offset, rc))130		rc = -EFAULT;131	else132		client->read_offset += rc;133 134 done:135	mutex_unlock(&client->lock);136 137	return rc;138}139 140static ssize_t occ_write(struct file *file, const char __user *buf,141			 size_t len, loff_t *offset)142{143	struct occ_client *client = file->private_data;144	size_t rlen, data_length;145	ssize_t rc;146	u8 *cmd;147 148	if (!client)149		return -ENODEV;150 151	if (len > (OCC_CMD_DATA_BYTES + 3) || len < 3)152		return -EINVAL;153 154	mutex_lock(&client->lock);155 156	/* Construct the command */157	cmd = client->buffer;158 159	/*160	 * Copy the user command (assume user data follows the occ command161	 * format)162	 * byte 0: command type163	 * bytes 1-2: data length (msb first)164	 * bytes 3-n: data165	 */166	if (copy_from_user(&cmd[1], buf, len)) {167		rc = -EFAULT;168		goto done;169	}170 171	/* Extract data length */172	data_length = (cmd[2] << 8) + cmd[3];173	if (data_length > OCC_CMD_DATA_BYTES) {174		rc = -EINVAL;175		goto done;176	}177 178	/* Submit command; 4 bytes before the data and 2 bytes after */179	rlen = PAGE_SIZE;180	rc = fsi_occ_submit(client->occ->dev, cmd, data_length + 6, cmd,181			    &rlen);182	if (rc)183		goto done;184 185	/* Set read tracking data */186	client->data_size = rlen;187	client->read_offset = 0;188 189	/* Done */190	rc = len;191 192 done:193	mutex_unlock(&client->lock);194 195	return rc;196}197 198static int occ_release(struct inode *inode, struct file *file)199{200	struct occ_client *client = file->private_data;201 202	put_device(client->occ->dev);203	free_page((unsigned long)client->buffer);204	kfree(client);205 206	return 0;207}208 209static const struct file_operations occ_fops = {210	.owner = THIS_MODULE,211	.open = occ_open,212	.read = occ_read,213	.write = occ_write,214	.release = occ_release,215};216 217static void occ_save_ffdc(struct occ *occ, __be32 *resp, size_t parsed_len,218			  size_t resp_len)219{220	if (resp_len > parsed_len) {221		size_t dh = resp_len - parsed_len;222		size_t ffdc_len = (dh - 1) * 4; /* SBE words are four bytes */223		__be32 *ffdc = &resp[parsed_len];224 225		if (ffdc_len > occ->client_buffer_size)226			ffdc_len = occ->client_buffer_size;227 228		memcpy(occ->client_buffer, ffdc, ffdc_len);229		occ->client_response_size = ffdc_len;230	}231}232 233static int occ_verify_checksum(struct occ *occ, struct occ_response *resp,234			       u16 data_length)235{236	/* Fetch the two bytes after the data for the checksum. */237	u16 checksum_resp = get_unaligned_be16(&resp->data[data_length]);238	u16 checksum;239	u16 i;240 241	checksum = resp->seq_no;242	checksum += resp->cmd_type;243	checksum += resp->return_status;244	checksum += (data_length >> 8) + (data_length & 0xFF);245 246	for (i = 0; i < data_length; ++i)247		checksum += resp->data[i];248 249	if (checksum != checksum_resp) {250		dev_err(occ->dev, "Bad checksum: %04x!=%04x\n", checksum,251			checksum_resp);252		return -EBADE;253	}254 255	return 0;256}257 258static int occ_getsram(struct occ *occ, u32 offset, void *data, ssize_t len)259{260	u32 data_len = ((len + 7) / 8) * 8;	/* must be multiples of 8 B */261	size_t cmd_len, parsed_len, resp_data_len;262	size_t resp_len = OCC_MAX_RESP_WORDS;263	__be32 *resp = occ->buffer;264	__be32 cmd[6];265	int idx = 0, rc;266 267	/*268	 * Magic sequence to do SBE getsram command. SBE will fetch data from269	 * specified SRAM address.270	 */271	switch (occ->version) {272	default:273	case occ_p9:274		cmd_len = 5;275		cmd[2] = cpu_to_be32(1);	/* Normal mode */276		cmd[3] = cpu_to_be32(OCC_P9_SRAM_RSP_ADDR + offset);277		break;278	case occ_p10:279		idx = 1;280		cmd_len = 6;281		cmd[2] = cpu_to_be32(OCC_P10_SRAM_MODE);282		cmd[3] = 0;283		cmd[4] = cpu_to_be32(OCC_P10_SRAM_RSP_ADDR + offset);284		break;285	}286 287	cmd[0] = cpu_to_be32(cmd_len);288	cmd[1] = cpu_to_be32(SBEFIFO_CMD_GET_OCC_SRAM);289	cmd[4 + idx] = cpu_to_be32(data_len);290 291	rc = sbefifo_submit(occ->sbefifo, cmd, cmd_len, resp, &resp_len);292	if (rc)293		return rc;294 295	rc = sbefifo_parse_status(occ->sbefifo, SBEFIFO_CMD_GET_OCC_SRAM,296				  resp, resp_len, &parsed_len);297	if (rc > 0) {298		dev_err(occ->dev, "SRAM read returned failure status: %08x\n",299			rc);300		occ_save_ffdc(occ, resp, parsed_len, resp_len);301		return -ECOMM;302	} else if (rc) {303		return rc;304	}305 306	resp_data_len = be32_to_cpu(resp[parsed_len - 1]);307	if (resp_data_len != data_len) {308		dev_err(occ->dev, "SRAM read expected %d bytes got %zd\n",309			data_len, resp_data_len);310		rc = -EBADMSG;311	} else {312		memcpy(data, resp, len);313	}314 315	return rc;316}317 318static int occ_putsram(struct occ *occ, const void *data, ssize_t len,319		       u8 seq_no, u16 checksum)320{321	u32 data_len = ((len + 7) / 8) * 8;	/* must be multiples of 8 B */322	size_t cmd_len, parsed_len, resp_data_len;323	size_t resp_len = OCC_MAX_RESP_WORDS;324	__be32 *buf = occ->buffer;325	u8 *byte_buf;326	int idx = 0, rc;327 328	cmd_len = (occ->version == occ_p10) ? 6 : 5;329	cmd_len += data_len >> 2;330 331	/*332	 * Magic sequence to do SBE putsram command. SBE will transfer333	 * data to specified SRAM address.334	 */335	buf[0] = cpu_to_be32(cmd_len);336	buf[1] = cpu_to_be32(SBEFIFO_CMD_PUT_OCC_SRAM);337 338	switch (occ->version) {339	default:340	case occ_p9:341		buf[2] = cpu_to_be32(1);	/* Normal mode */342		buf[3] = cpu_to_be32(OCC_P9_SRAM_CMD_ADDR);343		break;344	case occ_p10:345		idx = 1;346		buf[2] = cpu_to_be32(OCC_P10_SRAM_MODE);347		buf[3] = 0;348		buf[4] = cpu_to_be32(OCC_P10_SRAM_CMD_ADDR);349		break;350	}351 352	buf[4 + idx] = cpu_to_be32(data_len);353	memcpy(&buf[5 + idx], data, len);354 355	byte_buf = (u8 *)&buf[5 + idx];356	/*357	 * Overwrite the first byte with our sequence number and the last two358	 * bytes with the checksum.359	 */360	byte_buf[0] = seq_no;361	byte_buf[len - 2] = checksum >> 8;362	byte_buf[len - 1] = checksum & 0xff;363 364	rc = sbefifo_submit(occ->sbefifo, buf, cmd_len, buf, &resp_len);365	if (rc)366		return rc;367 368	rc = sbefifo_parse_status(occ->sbefifo, SBEFIFO_CMD_PUT_OCC_SRAM,369				  buf, resp_len, &parsed_len);370	if (rc > 0) {371		dev_err(occ->dev, "SRAM write returned failure status: %08x\n",372			rc);373		occ_save_ffdc(occ, buf, parsed_len, resp_len);374		return -ECOMM;375	} else if (rc) {376		return rc;377	}378 379	if (parsed_len != 1) {380		dev_err(occ->dev, "SRAM write response length invalid: %zd\n",381			parsed_len);382		rc = -EBADMSG;383	} else {384		resp_data_len = be32_to_cpu(buf[0]);385		if (resp_data_len != data_len) {386			dev_err(occ->dev,387				"SRAM write expected %d bytes got %zd\n",388				data_len, resp_data_len);389			rc = -EBADMSG;390		}391	}392 393	return rc;394}395 396static int occ_trigger_attn(struct occ *occ)397{398	__be32 *buf = occ->buffer;399	size_t cmd_len, parsed_len, resp_data_len;400	size_t resp_len = OCC_MAX_RESP_WORDS;401	int idx = 0, rc;402 403	switch (occ->version) {404	default:405	case occ_p9:406		cmd_len = 7;407		buf[2] = cpu_to_be32(3); /* Circular mode */408		buf[3] = 0;409		break;410	case occ_p10:411		idx = 1;412		cmd_len = 8;413		buf[2] = cpu_to_be32(0xd0); /* Circular mode, OCB Channel 1 */414		buf[3] = 0;415		buf[4] = 0;416		break;417	}418 419	buf[0] = cpu_to_be32(cmd_len);		/* Chip-op length in words */420	buf[1] = cpu_to_be32(SBEFIFO_CMD_PUT_OCC_SRAM);421	buf[4 + idx] = cpu_to_be32(8);		/* Data length in bytes */422	buf[5 + idx] = cpu_to_be32(0x20010000);	/* Trigger OCC attention */423	buf[6 + idx] = 0;424 425	rc = sbefifo_submit(occ->sbefifo, buf, cmd_len, buf, &resp_len);426	if (rc)427		return rc;428 429	rc = sbefifo_parse_status(occ->sbefifo, SBEFIFO_CMD_PUT_OCC_SRAM,430				  buf, resp_len, &parsed_len);431	if (rc > 0) {432		dev_err(occ->dev, "SRAM attn returned failure status: %08x\n",433			rc);434		occ_save_ffdc(occ, buf, parsed_len, resp_len);435		return -ECOMM;436	} else if (rc) {437		return rc;438	}439 440	if (parsed_len != 1) {441		dev_err(occ->dev, "SRAM attn response length invalid: %zd\n",442			parsed_len);443		rc = -EBADMSG;444	} else {445		resp_data_len = be32_to_cpu(buf[0]);446		if (resp_data_len != 8) {447			dev_err(occ->dev,448				"SRAM attn expected 8 bytes got %zd\n",449				resp_data_len);450			rc = -EBADMSG;451		}452	}453 454	return rc;455}456 457static bool fsi_occ_response_not_ready(struct occ_response *resp, u8 seq_no,458				       u8 cmd_type)459{460	return resp->return_status == OCC_RESP_CMD_IN_PRG ||461		resp->return_status == OCC_RESP_CRIT_INIT ||462		resp->seq_no != seq_no || resp->cmd_type != cmd_type;463}464 465int fsi_occ_submit(struct device *dev, const void *request, size_t req_len,466		   void *response, size_t *resp_len)467{468	const unsigned long timeout = msecs_to_jiffies(OCC_TIMEOUT_MS);469	const unsigned long wait_time =470		msecs_to_jiffies(OCC_CMD_IN_PRG_WAIT_MS);471	struct occ *occ = dev_get_drvdata(dev);472	struct occ_response *resp = response;473	size_t user_resp_len = *resp_len;474	u8 seq_no;475	u8 cmd_type;476	u16 checksum = 0;477	u16 resp_data_length;478	const u8 *byte_request = (const u8 *)request;479	unsigned long end;480	int rc;481	size_t i;482 483	*resp_len = 0;484 485	if (!occ)486		return -ENODEV;487 488	if (user_resp_len < 7) {489		dev_dbg(dev, "Bad resplen %zd\n", user_resp_len);490		return -EINVAL;491	}492 493	cmd_type = byte_request[1];494 495	/* Checksum the request, ignoring first byte (sequence number). */496	for (i = 1; i < req_len - 2; ++i)497		checksum += byte_request[i];498 499	rc = mutex_lock_interruptible(&occ->occ_lock);500	if (rc)501		return rc;502 503	occ->client_buffer = response;504	occ->client_buffer_size = user_resp_len;505	occ->client_response_size = 0;506 507	if (!occ->buffer) {508		rc = -ENOENT;509		goto done;510	}511 512	/*513	 * Get a sequence number and update the counter. Avoid a sequence514	 * number of 0 which would pass the response check below even if the515	 * OCC response is uninitialized. Any sequence number the user is516	 * trying to send is overwritten since this function is the only common517	 * interface to the OCC and therefore the only place we can guarantee518	 * unique sequence numbers.519	 */520	seq_no = occ->sequence_number++;521	if (!occ->sequence_number)522		occ->sequence_number = 1;523	checksum += seq_no;524 525	rc = occ_putsram(occ, request, req_len, seq_no, checksum);526	if (rc)527		goto done;528 529	rc = occ_trigger_attn(occ);530	if (rc)531		goto done;532 533	end = jiffies + timeout;534	while (true) {535		/* Read occ response header */536		rc = occ_getsram(occ, 0, resp, 8);537		if (rc)538			goto done;539 540		if (fsi_occ_response_not_ready(resp, seq_no, cmd_type)) {541			if (time_after(jiffies, end)) {542				dev_err(occ->dev,543					"resp timeout status=%02x seq=%d cmd=%d, our seq=%d cmd=%d\n",544					resp->return_status, resp->seq_no,545					resp->cmd_type, seq_no, cmd_type);546				rc = -ETIMEDOUT;547				goto done;548			}549 550			set_current_state(TASK_UNINTERRUPTIBLE);551			schedule_timeout(wait_time);552		} else {553			/* Extract size of response data */554			resp_data_length =555				get_unaligned_be16(&resp->data_length);556 557			/*558			 * Message size is data length + 5 bytes header + 2559			 * bytes checksum560			 */561			if ((resp_data_length + 7) > user_resp_len) {562				rc = -EMSGSIZE;563				goto done;564			}565 566			/*567			 * Get the entire response including the header again,568			 * in case it changed569			 */570			if (resp_data_length > 1) {571				rc = occ_getsram(occ, 0, resp,572						 resp_data_length + 7);573				if (rc)574					goto done;575 576				if (!fsi_occ_response_not_ready(resp, seq_no,577								cmd_type))578					break;579			} else {580				break;581			}582		}583	}584 585	dev_dbg(dev, "resp_status=%02x resp_data_len=%d\n",586		resp->return_status, resp_data_length);587 588	rc = occ_verify_checksum(occ, resp, resp_data_length);589	if (rc)590		goto done;591 592	occ->client_response_size = resp_data_length + 7;593 594 done:595	*resp_len = occ->client_response_size;596	mutex_unlock(&occ->occ_lock);597 598	return rc;599}600EXPORT_SYMBOL_GPL(fsi_occ_submit);601 602static int occ_unregister_platform_child(struct device *dev, void *data)603{604	struct platform_device *hwmon_dev = to_platform_device(dev);605 606	platform_device_unregister(hwmon_dev);607 608	return 0;609}610 611static int occ_unregister_of_child(struct device *dev, void *data)612{613	struct platform_device *hwmon_dev = to_platform_device(dev);614 615	of_device_unregister(hwmon_dev);616	if (dev->of_node)617		of_node_clear_flag(dev->of_node, OF_POPULATED);618 619	return 0;620}621 622static int occ_probe(struct platform_device *pdev)623{624	int rc;625	u32 reg;626	char child_name[32];627	struct occ *occ;628	struct platform_device *hwmon_dev = NULL;629	struct device_node *hwmon_node;630	struct device *dev = &pdev->dev;631	struct platform_device_info hwmon_dev_info = {632		.parent = dev,633		.name = "occ-hwmon",634	};635 636	occ = devm_kzalloc(dev, sizeof(*occ), GFP_KERNEL);637	if (!occ)638		return -ENOMEM;639 640	/* SBE words are always four bytes */641	occ->buffer = kvmalloc(OCC_MAX_RESP_WORDS * 4, GFP_KERNEL);642	if (!occ->buffer)643		return -ENOMEM;644 645	occ->version = (uintptr_t)of_device_get_match_data(dev);646	occ->dev = dev;647	occ->sbefifo = dev->parent;648	/*649	 * Quickly derive a pseudo-random number from jiffies so that650	 * re-probing the driver doesn't accidentally overlap sequence numbers.651	 */652	occ->sequence_number = (u8)((jiffies % 0xff) + 1);653	mutex_init(&occ->occ_lock);654 655	if (dev->of_node) {656		rc = of_property_read_u32(dev->of_node, "reg", &reg);657		if (!rc) {658			/* make sure we don't have a duplicate from dts */659			occ->idx = ida_alloc_range(&occ_ida, reg, reg,660						   GFP_KERNEL);661			if (occ->idx < 0)662				occ->idx = ida_alloc_min(&occ_ida, 1,663							 GFP_KERNEL);664		} else {665			occ->idx = ida_alloc_min(&occ_ida, 1, GFP_KERNEL);666		}667	} else {668		occ->idx = ida_alloc_min(&occ_ida, 1, GFP_KERNEL);669	}670 671	platform_set_drvdata(pdev, occ);672 673	snprintf(occ->name, sizeof(occ->name), "occ%d", occ->idx);674	occ->mdev.fops = &occ_fops;675	occ->mdev.minor = MISC_DYNAMIC_MINOR;676	occ->mdev.name = occ->name;677	occ->mdev.parent = dev;678 679	rc = misc_register(&occ->mdev);680	if (rc) {681		dev_err(dev, "failed to register miscdevice: %d\n", rc);682		ida_free(&occ_ida, occ->idx);683		kvfree(occ->buffer);684		return rc;685	}686 687	hwmon_node = of_get_child_by_name(dev->of_node, hwmon_dev_info.name);688	if (hwmon_node) {689		snprintf(child_name, sizeof(child_name), "%s.%d", hwmon_dev_info.name, occ->idx);690		hwmon_dev = of_platform_device_create(hwmon_node, child_name, dev);691		of_node_put(hwmon_node);692	}693 694	if (!hwmon_dev) {695		occ->platform_hwmon = true;696		hwmon_dev_info.id = occ->idx;697		hwmon_dev = platform_device_register_full(&hwmon_dev_info);698		if (IS_ERR(hwmon_dev))699			dev_warn(dev, "failed to create hwmon device\n");700	}701 702	return 0;703}704 705static void occ_remove(struct platform_device *pdev)706{707	struct occ *occ = platform_get_drvdata(pdev);708 709	misc_deregister(&occ->mdev);710 711	mutex_lock(&occ->occ_lock);712	kvfree(occ->buffer);713	occ->buffer = NULL;714	mutex_unlock(&occ->occ_lock);715 716	if (occ->platform_hwmon)717		device_for_each_child(&pdev->dev, NULL, occ_unregister_platform_child);718	else719		device_for_each_child(&pdev->dev, NULL, occ_unregister_of_child);720 721	ida_free(&occ_ida, occ->idx);722}723 724static const struct of_device_id occ_match[] = {725	{726		.compatible = "ibm,p9-occ",727		.data = (void *)occ_p9728	},729	{730		.compatible = "ibm,p10-occ",731		.data = (void *)occ_p10732	},733	{ },734};735MODULE_DEVICE_TABLE(of, occ_match);736 737static struct platform_driver occ_driver = {738	.driver = {739		.name = "occ",740		.of_match_table	= occ_match,741	},742	.probe	= occ_probe,743	.remove_new = occ_remove,744};745 746static int occ_init(void)747{748	return platform_driver_register(&occ_driver);749}750 751static void occ_exit(void)752{753	platform_driver_unregister(&occ_driver);754 755	ida_destroy(&occ_ida);756}757 758module_init(occ_init);759module_exit(occ_exit);760 761MODULE_AUTHOR("Eddie James <eajames@linux.ibm.com>");762MODULE_DESCRIPTION("BMC P9 OCC driver");763MODULE_LICENSE("GPL");764