brintos

brintos / linux-shallow public Read only

0
0
Text · 13.8 KiB · 42bd8e7 Raw
569 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 *  Driver for the NXP SAA7164 PCIe bridge4 *5 *  Copyright (c) 2010-2015 Steven Toth <stoth@kernellabs.com>6 */7 8#include <linux/wait.h>9 10#include "saa7164.h"11 12static int saa7164_cmd_alloc_seqno(struct saa7164_dev *dev)13{14	int i, ret = -1;15 16	mutex_lock(&dev->lock);17	for (i = 0; i < SAA_CMD_MAX_MSG_UNITS; i++) {18		if (dev->cmds[i].inuse == 0) {19			dev->cmds[i].inuse = 1;20			dev->cmds[i].signalled = 0;21			dev->cmds[i].timeout = 0;22			ret = dev->cmds[i].seqno;23			break;24		}25	}26	mutex_unlock(&dev->lock);27 28	return ret;29}30 31static void saa7164_cmd_free_seqno(struct saa7164_dev *dev, u8 seqno)32{33	mutex_lock(&dev->lock);34	if ((dev->cmds[seqno].inuse == 1) &&35		(dev->cmds[seqno].seqno == seqno)) {36		dev->cmds[seqno].inuse = 0;37		dev->cmds[seqno].signalled = 0;38		dev->cmds[seqno].timeout = 0;39	}40	mutex_unlock(&dev->lock);41}42 43static void saa7164_cmd_timeout_seqno(struct saa7164_dev *dev, u8 seqno)44{45	mutex_lock(&dev->lock);46	if ((dev->cmds[seqno].inuse == 1) &&47		(dev->cmds[seqno].seqno == seqno)) {48		dev->cmds[seqno].timeout = 1;49	}50	mutex_unlock(&dev->lock);51}52 53static u32 saa7164_cmd_timeout_get(struct saa7164_dev *dev, u8 seqno)54{55	int ret = 0;56 57	mutex_lock(&dev->lock);58	if ((dev->cmds[seqno].inuse == 1) &&59		(dev->cmds[seqno].seqno == seqno)) {60		ret = dev->cmds[seqno].timeout;61	}62	mutex_unlock(&dev->lock);63 64	return ret;65}66 67/* Commands to the f/w get marshelled to/from this code then onto the PCI68 * -bus/c running buffer. */69int saa7164_irq_dequeue(struct saa7164_dev *dev)70{71	int ret = SAA_OK, i = 0;72	u32 timeout;73	wait_queue_head_t *q = NULL;74	u8 tmp[512];75	dprintk(DBGLVL_CMD, "%s()\n", __func__);76 77	/* While any outstand message on the bus exists... */78	do {79 80		/* Peek the msg bus */81		struct tmComResInfo tRsp = { 0, 0, 0, 0, 0, 0 };82		ret = saa7164_bus_get(dev, &tRsp, NULL, 1);83		if (ret != SAA_OK)84			break;85 86		q = &dev->cmds[tRsp.seqno].wait;87		timeout = saa7164_cmd_timeout_get(dev, tRsp.seqno);88		dprintk(DBGLVL_CMD, "%s() timeout = %d\n", __func__, timeout);89		if (!timeout) {90			dprintk(DBGLVL_CMD,91				"%s() signalled seqno(%d) (for dequeue)\n",92				__func__, tRsp.seqno);93			dev->cmds[tRsp.seqno].signalled = 1;94			wake_up(q);95		} else {96			printk(KERN_ERR97				"%s() found timed out command on the bus\n",98					__func__);99 100			/* Clean the bus */101			ret = saa7164_bus_get(dev, &tRsp, &tmp, 0);102			printk(KERN_ERR "%s() ret = %x\n", __func__, ret);103			if (ret == SAA_ERR_EMPTY)104				/* Someone else already fetched the response */105				return SAA_OK;106 107			if (ret != SAA_OK)108				return ret;109		}110 111		/* It's unlikely to have more than 4 or 5 pending messages,112		 * ensure we exit at some point regardless.113		 */114	} while (i++ < 32);115 116	return ret;117}118 119/* Commands to the f/w get marshelled to/from this code then onto the PCI120 * -bus/c running buffer. */121static int saa7164_cmd_dequeue(struct saa7164_dev *dev)122{123	int ret;124	u32 timeout;125	wait_queue_head_t *q = NULL;126	u8 tmp[512];127	dprintk(DBGLVL_CMD, "%s()\n", __func__);128 129	while (true) {130 131		struct tmComResInfo tRsp = { 0, 0, 0, 0, 0, 0 };132		ret = saa7164_bus_get(dev, &tRsp, NULL, 1);133		if (ret == SAA_ERR_EMPTY)134			return SAA_OK;135 136		if (ret != SAA_OK)137			return ret;138 139		q = &dev->cmds[tRsp.seqno].wait;140		timeout = saa7164_cmd_timeout_get(dev, tRsp.seqno);141		dprintk(DBGLVL_CMD, "%s() timeout = %d\n", __func__, timeout);142		if (timeout) {143			printk(KERN_ERR "found timed out command on the bus\n");144 145			/* Clean the bus */146			ret = saa7164_bus_get(dev, &tRsp, &tmp, 0);147			printk(KERN_ERR "ret = %x\n", ret);148			if (ret == SAA_ERR_EMPTY)149				/* Someone else already fetched the response */150				return SAA_OK;151 152			if (ret != SAA_OK)153				return ret;154 155			if (tRsp.flags & PVC_CMDFLAG_CONTINUE)156				printk(KERN_ERR "split response\n");157			else158				saa7164_cmd_free_seqno(dev, tRsp.seqno);159 160			printk(KERN_ERR " timeout continue\n");161			continue;162		}163 164		dprintk(DBGLVL_CMD, "%s() signalled seqno(%d) (for dequeue)\n",165			__func__, tRsp.seqno);166		dev->cmds[tRsp.seqno].signalled = 1;167		wake_up(q);168		return SAA_OK;169	}170}171 172static int saa7164_cmd_set(struct saa7164_dev *dev, struct tmComResInfo *msg,173			   void *buf)174{175	struct tmComResBusInfo *bus = &dev->bus;176	u8 cmd_sent;177	u16 size, idx;178	u32 cmds;179	void *tmp;180	int ret = -1;181 182	if (!msg) {183		printk(KERN_ERR "%s() !msg\n", __func__);184		return SAA_ERR_BAD_PARAMETER;185	}186 187	mutex_lock(&dev->cmds[msg->id].lock);188 189	size = msg->size;190	cmds = size / bus->m_wMaxReqSize;191	if (size % bus->m_wMaxReqSize == 0)192		cmds -= 1;193 194	cmd_sent = 0;195 196	/* Split the request into smaller chunks */197	for (idx = 0; idx < cmds; idx++) {198 199		msg->flags |= SAA_CMDFLAG_CONTINUE;200		msg->size = bus->m_wMaxReqSize;201		tmp = buf + idx * bus->m_wMaxReqSize;202 203		ret = saa7164_bus_set(dev, msg, tmp);204		if (ret != SAA_OK) {205			printk(KERN_ERR "%s() set failed %d\n", __func__, ret);206 207			if (cmd_sent) {208				ret = SAA_ERR_BUSY;209				goto out;210			}211			ret = SAA_ERR_OVERFLOW;212			goto out;213		}214		cmd_sent = 1;215	}216 217	/* If not the last command... */218	if (idx != 0)219		msg->flags &= ~SAA_CMDFLAG_CONTINUE;220 221	msg->size = size - idx * bus->m_wMaxReqSize;222 223	ret = saa7164_bus_set(dev, msg, buf + idx * bus->m_wMaxReqSize);224	if (ret != SAA_OK) {225		printk(KERN_ERR "%s() set last failed %d\n", __func__, ret);226 227		if (cmd_sent) {228			ret = SAA_ERR_BUSY;229			goto out;230		}231		ret = SAA_ERR_OVERFLOW;232		goto out;233	}234	ret = SAA_OK;235 236out:237	mutex_unlock(&dev->cmds[msg->id].lock);238	return ret;239}240 241/* Wait for a signal event, without holding a mutex. Either return TIMEOUT if242 * the event never occurred, or SAA_OK if it was signaled during the wait.243 */244static int saa7164_cmd_wait(struct saa7164_dev *dev, u8 seqno)245{246	wait_queue_head_t *q = NULL;247	int ret = SAA_BUS_TIMEOUT;248	unsigned long stamp;249	int r;250 251	if (saa_debug >= 4)252		saa7164_bus_dump(dev);253 254	dprintk(DBGLVL_CMD, "%s(seqno=%d)\n", __func__, seqno);255 256	mutex_lock(&dev->lock);257	if ((dev->cmds[seqno].inuse == 1) &&258		(dev->cmds[seqno].seqno == seqno)) {259		q = &dev->cmds[seqno].wait;260	}261	mutex_unlock(&dev->lock);262 263	if (q) {264		/* If we haven't been signalled we need to wait */265		if (dev->cmds[seqno].signalled == 0) {266			stamp = jiffies;267			dprintk(DBGLVL_CMD,268				"%s(seqno=%d) Waiting (signalled=%d)\n",269				__func__, seqno, dev->cmds[seqno].signalled);270 271			/* Wait for signalled to be flagged or timeout */272			/* In a highly stressed system this can easily extend273			 * into multiple seconds before the deferred worker274			 * is scheduled, and we're woken up via signal.275			 * We typically are signalled in < 50ms but it can276			 * take MUCH longer.277			 */278			wait_event_timeout(*q, dev->cmds[seqno].signalled,279				(HZ * waitsecs));280			r = time_before(jiffies, stamp + (HZ * waitsecs));281			if (r)282				ret = SAA_OK;283			else284				saa7164_cmd_timeout_seqno(dev, seqno);285 286			dprintk(DBGLVL_CMD, "%s(seqno=%d) Waiting res = %d (signalled=%d)\n",287				__func__, seqno, r,288				dev->cmds[seqno].signalled);289		} else290			ret = SAA_OK;291	} else292		printk(KERN_ERR "%s(seqno=%d) seqno is invalid\n",293			__func__, seqno);294 295	return ret;296}297 298void saa7164_cmd_signal(struct saa7164_dev *dev, u8 seqno)299{300	int i;301	dprintk(DBGLVL_CMD, "%s()\n", __func__);302 303	mutex_lock(&dev->lock);304	for (i = 0; i < SAA_CMD_MAX_MSG_UNITS; i++) {305		if (dev->cmds[i].inuse == 1) {306			dprintk(DBGLVL_CMD,307				"seqno %d inuse, sig = %d, t/out = %d\n",308				dev->cmds[i].seqno,309				dev->cmds[i].signalled,310				dev->cmds[i].timeout);311		}312	}313 314	for (i = 0; i < SAA_CMD_MAX_MSG_UNITS; i++) {315		if ((dev->cmds[i].inuse == 1) && ((i == 0) ||316			(dev->cmds[i].signalled) || (dev->cmds[i].timeout))) {317			dprintk(DBGLVL_CMD, "%s(seqno=%d) calling wake_up\n",318				__func__, i);319			dev->cmds[i].signalled = 1;320			wake_up(&dev->cmds[i].wait);321		}322	}323	mutex_unlock(&dev->lock);324}325 326int saa7164_cmd_send(struct saa7164_dev *dev, u8 id, enum tmComResCmd command,327	u16 controlselector, u16 size, void *buf)328{329	struct tmComResInfo command_t, *pcommand_t;330	struct tmComResInfo response_t, *presponse_t;331	u8 errdata[256];332	u16 resp_dsize;333	u16 data_recd;334	u32 loop;335	int ret;336	int safety = 0;337 338	dprintk(DBGLVL_CMD, "%s(unitid = %s (%d) , command = 0x%x, sel = 0x%x)\n",339		__func__, saa7164_unitid_name(dev, id), id,340		command, controlselector);341 342	if ((size == 0) || (buf == NULL)) {343		printk(KERN_ERR "%s() Invalid param\n", __func__);344		return SAA_ERR_BAD_PARAMETER;345	}346 347	/* Prepare some basic command/response structures */348	memset(&command_t, 0, sizeof(command_t));349	memset(&response_t, 0, sizeof(response_t));350	pcommand_t = &command_t;351	presponse_t = &response_t;352	command_t.id = id;353	command_t.command = command;354	command_t.controlselector = controlselector;355	command_t.size = size;356 357	/* Allocate a unique sequence number */358	ret = saa7164_cmd_alloc_seqno(dev);359	if (ret < 0) {360		printk(KERN_ERR "%s() No free sequences\n", __func__);361		ret = SAA_ERR_NO_RESOURCES;362		goto out;363	}364 365	command_t.seqno = (u8)ret;366 367	/* Send Command */368	resp_dsize = size;369	pcommand_t->size = size;370 371	dprintk(DBGLVL_CMD, "%s() pcommand_t.seqno = %d\n",372		__func__, pcommand_t->seqno);373 374	dprintk(DBGLVL_CMD, "%s() pcommand_t.size = %d\n",375		__func__, pcommand_t->size);376 377	ret = saa7164_cmd_set(dev, pcommand_t, buf);378	if (ret != SAA_OK) {379		printk(KERN_ERR "%s() set command failed %d\n", __func__, ret);380 381		if (ret != SAA_ERR_BUSY)382			saa7164_cmd_free_seqno(dev, pcommand_t->seqno);383		else384			/* Flag a timeout, because at least one385			 * command was sent */386			saa7164_cmd_timeout_seqno(dev, pcommand_t->seqno);387 388		goto out;389	}390 391	/* With split responses we have to collect the msgs piece by piece */392	data_recd = 0;393	loop = 1;394	while (loop) {395		dprintk(DBGLVL_CMD, "%s() loop\n", __func__);396 397		ret = saa7164_cmd_wait(dev, pcommand_t->seqno);398		dprintk(DBGLVL_CMD, "%s() loop ret = %d\n", __func__, ret);399 400		/* if power is down and this is not a power command ... */401 402		if (ret == SAA_BUS_TIMEOUT) {403			printk(KERN_ERR "Event timed out\n");404			saa7164_cmd_timeout_seqno(dev, pcommand_t->seqno);405			return ret;406		}407 408		if (ret != SAA_OK) {409			printk(KERN_ERR "spurious error\n");410			return ret;411		}412 413		/* Peek response */414		ret = saa7164_bus_get(dev, presponse_t, NULL, 1);415		if (ret == SAA_ERR_EMPTY) {416			dprintk(4, "%s() SAA_ERR_EMPTY\n", __func__);417			continue;418		}419		if (ret != SAA_OK) {420			printk(KERN_ERR "peek failed\n");421			return ret;422		}423 424		dprintk(DBGLVL_CMD, "%s() presponse_t->seqno = %d\n",425			__func__, presponse_t->seqno);426 427		dprintk(DBGLVL_CMD, "%s() presponse_t->flags = 0x%x\n",428			__func__, presponse_t->flags);429 430		dprintk(DBGLVL_CMD, "%s() presponse_t->size = %d\n",431			__func__, presponse_t->size);432 433		/* Check if the response was for our command */434		if (presponse_t->seqno != pcommand_t->seqno) {435 436			dprintk(DBGLVL_CMD,437				"wrong event: seqno = %d, expected seqno = %d, will dequeue regardless\n",438				presponse_t->seqno, pcommand_t->seqno);439 440			ret = saa7164_cmd_dequeue(dev);441			if (ret != SAA_OK) {442				printk(KERN_ERR "dequeue failed, ret = %d\n",443					ret);444				if (safety++ > 16) {445					printk(KERN_ERR446					"dequeue exceeded, safety exit\n");447					return SAA_ERR_BUSY;448				}449			}450 451			continue;452		}453 454		if ((presponse_t->flags & PVC_RESPONSEFLAG_ERROR) != 0) {455 456			memset(&errdata[0], 0, sizeof(errdata));457 458			ret = saa7164_bus_get(dev, presponse_t, &errdata[0], 0);459			if (ret != SAA_OK) {460				printk(KERN_ERR "get error(2)\n");461				return ret;462			}463 464			saa7164_cmd_free_seqno(dev, pcommand_t->seqno);465 466			dprintk(DBGLVL_CMD, "%s() errdata %02x%02x%02x%02x\n",467				__func__, errdata[0], errdata[1], errdata[2],468				errdata[3]);469 470			/* Map error codes */471			dprintk(DBGLVL_CMD, "%s() cmd, error code  = 0x%x\n",472				__func__, errdata[0]);473 474			switch (errdata[0]) {475			case PVC_ERRORCODE_INVALID_COMMAND:476				dprintk(DBGLVL_CMD, "%s() INVALID_COMMAND\n",477					__func__);478				ret = SAA_ERR_INVALID_COMMAND;479				break;480			case PVC_ERRORCODE_INVALID_DATA:481				dprintk(DBGLVL_CMD, "%s() INVALID_DATA\n",482					__func__);483				ret = SAA_ERR_BAD_PARAMETER;484				break;485			case PVC_ERRORCODE_TIMEOUT:486				dprintk(DBGLVL_CMD, "%s() TIMEOUT\n", __func__);487				ret = SAA_ERR_TIMEOUT;488				break;489			case PVC_ERRORCODE_NAK:490				dprintk(DBGLVL_CMD, "%s() NAK\n", __func__);491				ret = SAA_ERR_NULL_PACKET;492				break;493			case PVC_ERRORCODE_UNKNOWN:494			case PVC_ERRORCODE_INVALID_CONTROL:495				dprintk(DBGLVL_CMD,496					"%s() UNKNOWN OR INVALID CONTROL\n",497					__func__);498				ret = SAA_ERR_NOT_SUPPORTED;499				break;500			default:501				dprintk(DBGLVL_CMD, "%s() UNKNOWN\n", __func__);502				ret = SAA_ERR_NOT_SUPPORTED;503			}504 505			/* See of other commands are on the bus */506			if (saa7164_cmd_dequeue(dev) != SAA_OK)507				printk(KERN_ERR "dequeue(2) failed\n");508 509			return ret;510		}511 512		/* If response is invalid */513		if ((presponse_t->id != pcommand_t->id) ||514			(presponse_t->command != pcommand_t->command) ||515			(presponse_t->controlselector !=516				pcommand_t->controlselector) ||517			(((resp_dsize - data_recd) != presponse_t->size) &&518				!(presponse_t->flags & PVC_CMDFLAG_CONTINUE)) ||519			((resp_dsize - data_recd) < presponse_t->size)) {520 521			/* Invalid */522			dprintk(DBGLVL_CMD, "%s() Invalid\n", __func__);523			ret = saa7164_bus_get(dev, presponse_t, NULL, 0);524			if (ret != SAA_OK) {525				printk(KERN_ERR "get failed\n");526				return ret;527			}528 529			/* See of other commands are on the bus */530			if (saa7164_cmd_dequeue(dev) != SAA_OK)531				printk(KERN_ERR "dequeue(3) failed\n");532			continue;533		}534 535		/* OK, now we're actually getting out correct response */536		ret = saa7164_bus_get(dev, presponse_t, buf + data_recd, 0);537		if (ret != SAA_OK) {538			printk(KERN_ERR "get failed\n");539			return ret;540		}541 542		data_recd = presponse_t->size + data_recd;543		if (resp_dsize == data_recd) {544			dprintk(DBGLVL_CMD, "%s() Resp recd\n", __func__);545			break;546		}547 548		/* See of other commands are on the bus */549		if (saa7164_cmd_dequeue(dev) != SAA_OK)550			printk(KERN_ERR "dequeue(3) failed\n");551	} /* (loop) */552 553	/* Release the sequence number allocation */554	saa7164_cmd_free_seqno(dev, pcommand_t->seqno);555 556	/* if powerdown signal all pending commands */557 558	dprintk(DBGLVL_CMD, "%s() Calling dequeue then exit\n", __func__);559 560	/* See of other commands are on the bus */561	if (saa7164_cmd_dequeue(dev) != SAA_OK)562		printk(KERN_ERR "dequeue(4) failed\n");563 564	ret = SAA_OK;565out:566	return ret;567}568 569