Commit e34f4262 authored by Bjorn Helgaas's avatar Bjorn Helgaas
Browse files

Merge branch 'pci/switchtec'

- Return error to application when command execution fails because an
  out-of-band reset has cleared the device BARs, Memory Space Enable, etc
  (Kelvin Cao)

- Fix MRPC error status handling issue (Kelvin Cao)

- Mask out other bits when reading of management VEP instance ID (Kelvin
  Cao)

- Return EOPNOTSUPP instead of ENOTSUPP from sysfs show functions (Kelvin
  Cao)

- Add check of event support (Logan Gunthorpe)

* pci/switchtec:
  PCI/switchtec: Add check of event support
  PCI/switchtec: Replace ENOTSUPP with EOPNOTSUPP
  PCI/switchtec: Update the way of getting management VEP instance ID
  PCI/switchtec: Fix a MRPC error status handling issue
  PCI/switchtec: Error out MRPC execution when MMIO reads fail
parents 1ebec13f 9f37ab04
Loading
Loading
Loading
Loading
+78 −17
Original line number Diff line number Diff line
@@ -45,6 +45,7 @@ enum mrpc_state {
	MRPC_QUEUED,
	MRPC_RUNNING,
	MRPC_DONE,
	MRPC_IO_ERROR,
};

struct switchtec_user {
@@ -66,6 +67,19 @@ struct switchtec_user {
	int event_cnt;
};

/*
 * The MMIO reads to the device_id register should always return the device ID
 * of the device, otherwise the firmware is probably stuck or unreachable
 * due to a firmware reset which clears PCI state including the BARs and Memory
 * Space Enable bits.
 */
static int is_firmware_running(struct switchtec_dev *stdev)
{
	u32 device = ioread32(&stdev->mmio_sys_info->device_id);

	return stdev->pdev->device == device;
}

static struct switchtec_user *stuser_create(struct switchtec_dev *stdev)
{
	struct switchtec_user *stuser;
@@ -113,6 +127,7 @@ static void stuser_set_state(struct switchtec_user *stuser,
		[MRPC_QUEUED] = "QUEUED",
		[MRPC_RUNNING] = "RUNNING",
		[MRPC_DONE] = "DONE",
		[MRPC_IO_ERROR] = "IO_ERROR",
	};

	stuser->state = state;
@@ -184,9 +199,26 @@ static int mrpc_queue_cmd(struct switchtec_user *stuser)
	return 0;
}

static void mrpc_cleanup_cmd(struct switchtec_dev *stdev)
{
	/* requires the mrpc_mutex to already be held when called */

	struct switchtec_user *stuser = list_entry(stdev->mrpc_queue.next,
						   struct switchtec_user, list);

	stuser->cmd_done = true;
	wake_up_interruptible(&stuser->cmd_comp);
	list_del_init(&stuser->list);
	stuser_put(stuser);
	stdev->mrpc_busy = 0;

	mrpc_cmd_submit(stdev);
}

static void mrpc_complete_cmd(struct switchtec_dev *stdev)
{
	/* requires the mrpc_mutex to already be held when called */

	struct switchtec_user *stuser;

	if (list_empty(&stdev->mrpc_queue))
@@ -206,7 +238,8 @@ static void mrpc_complete_cmd(struct switchtec_dev *stdev)
	stuser_set_state(stuser, MRPC_DONE);
	stuser->return_code = 0;

	if (stuser->status != SWITCHTEC_MRPC_STATUS_DONE)
	if (stuser->status != SWITCHTEC_MRPC_STATUS_DONE &&
	    stuser->status != SWITCHTEC_MRPC_STATUS_ERROR)
		goto out;

	if (stdev->dma_mrpc)
@@ -223,13 +256,7 @@ static void mrpc_complete_cmd(struct switchtec_dev *stdev)
		memcpy_fromio(stuser->data, &stdev->mmio_mrpc->output_data,
			      stuser->read_len);
out:
	stuser->cmd_done = true;
	wake_up_interruptible(&stuser->cmd_comp);
	list_del_init(&stuser->list);
	stuser_put(stuser);
	stdev->mrpc_busy = 0;

	mrpc_cmd_submit(stdev);
	mrpc_cleanup_cmd(stdev);
}

static void mrpc_event_work(struct work_struct *work)
@@ -246,6 +273,23 @@ static void mrpc_event_work(struct work_struct *work)
	mutex_unlock(&stdev->mrpc_mutex);
}

static void mrpc_error_complete_cmd(struct switchtec_dev *stdev)
{
	/* requires the mrpc_mutex to already be held when called */

	struct switchtec_user *stuser;

	if (list_empty(&stdev->mrpc_queue))
		return;

	stuser = list_entry(stdev->mrpc_queue.next,
			    struct switchtec_user, list);

	stuser_set_state(stuser, MRPC_IO_ERROR);

	mrpc_cleanup_cmd(stdev);
}

static void mrpc_timeout_work(struct work_struct *work)
{
	struct switchtec_dev *stdev;
@@ -257,6 +301,11 @@ static void mrpc_timeout_work(struct work_struct *work)

	mutex_lock(&stdev->mrpc_mutex);

	if (!is_firmware_running(stdev)) {
		mrpc_error_complete_cmd(stdev);
		goto out;
	}

	if (stdev->dma_mrpc)
		status = stdev->dma_mrpc->status;
	else
@@ -327,7 +376,7 @@ static ssize_t field ## _show(struct device *dev, \
		return io_string_show(buf, &si->gen4.field, \
				      sizeof(si->gen4.field)); \
	else \
		return -ENOTSUPP; \
		return -EOPNOTSUPP; \
} \
\
static DEVICE_ATTR_RO(field)
@@ -544,6 +593,11 @@ static ssize_t switchtec_dev_read(struct file *filp, char __user *data,
	if (rc)
		return rc;

	if (stuser->state == MRPC_IO_ERROR) {
		mutex_unlock(&stdev->mrpc_mutex);
		return -EIO;
	}

	if (stuser->state != MRPC_DONE) {
		mutex_unlock(&stdev->mrpc_mutex);
		return -EBADE;
@@ -569,7 +623,8 @@ static ssize_t switchtec_dev_read(struct file *filp, char __user *data,
out:
	mutex_unlock(&stdev->mrpc_mutex);

	if (stuser->status == SWITCHTEC_MRPC_STATUS_DONE)
	if (stuser->status == SWITCHTEC_MRPC_STATUS_DONE ||
	    stuser->status == SWITCHTEC_MRPC_STATUS_ERROR)
		return size;
	else if (stuser->status == SWITCHTEC_MRPC_STATUS_INTERRUPTED)
		return -ENXIO;
@@ -613,7 +668,7 @@ static int ioctl_flash_info(struct switchtec_dev *stdev,
		info.flash_length = ioread32(&fi->gen4.flash_length);
		info.num_partitions = SWITCHTEC_NUM_PARTITIONS_GEN4;
	} else {
		return -ENOTSUPP;
		return -EOPNOTSUPP;
	}

	if (copy_to_user(uinfo, &info, sizeof(info)))
@@ -821,7 +876,7 @@ static int ioctl_flash_part_info(struct switchtec_dev *stdev,
		if (ret)
			return ret;
	} else {
		return -ENOTSUPP;
		return -EOPNOTSUPP;
	}

	if (copy_to_user(uinfo, &info, sizeof(info)))
@@ -969,6 +1024,9 @@ static int event_ctl(struct switchtec_dev *stdev,
		return PTR_ERR(reg);

	hdr = ioread32(reg);
	if (hdr & SWITCHTEC_EVENT_NOT_SUPP)
		return -EOPNOTSUPP;

	for (i = 0; i < ARRAY_SIZE(ctl->data); i++)
		ctl->data[i] = ioread32(&reg[i + 1]);

@@ -1041,7 +1099,7 @@ static int ioctl_event_ctl(struct switchtec_dev *stdev,
		for (ctl.index = 0; ctl.index < nr_idxs; ctl.index++) {
			ctl.flags = event_flags;
			ret = event_ctl(stdev, &ctl);
			if (ret < 0)
			if (ret < 0 && ret != -EOPNOTSUPP)
				return ret;
		}
	} else {
@@ -1078,7 +1136,7 @@ static int ioctl_pff_to_port(struct switchtec_dev *stdev,
			break;
		}

		reg = ioread32(&pcfg->vep_pff_inst_id);
		reg = ioread32(&pcfg->vep_pff_inst_id) & 0xFF;
		if (reg == p.pff) {
			p.port = SWITCHTEC_IOCTL_PFF_VEP;
			break;
@@ -1124,7 +1182,7 @@ static int ioctl_port_to_pff(struct switchtec_dev *stdev,
		p.pff = ioread32(&pcfg->usp_pff_inst_id);
		break;
	case SWITCHTEC_IOCTL_PFF_VEP:
		p.pff = ioread32(&pcfg->vep_pff_inst_id);
		p.pff = ioread32(&pcfg->vep_pff_inst_id) & 0xFF;
		break;
	default:
		if (p.port > ARRAY_SIZE(pcfg->dsp_pff_inst_id))
@@ -1348,6 +1406,9 @@ static int mask_event(struct switchtec_dev *stdev, int eid, int idx)
	hdr_reg = event_regs[eid].map_reg(stdev, off, idx);
	hdr = ioread32(hdr_reg);

	if (hdr & SWITCHTEC_EVENT_NOT_SUPP)
		return 0;

	if (!(hdr & SWITCHTEC_EVENT_OCCURRED && hdr & SWITCHTEC_EVENT_EN_IRQ))
		return 0;

@@ -1498,7 +1559,7 @@ static void init_pff(struct switchtec_dev *stdev)
	if (reg < stdev->pff_csr_count)
		stdev->pff_local[reg] = 1;

	reg = ioread32(&pcfg->vep_pff_inst_id);
	reg = ioread32(&pcfg->vep_pff_inst_id) & 0xFF;
	if (reg < stdev->pff_csr_count)
		stdev->pff_local[reg] = 1;

@@ -1556,7 +1617,7 @@ static int switchtec_init_pci(struct switchtec_dev *stdev,
	else if (stdev->gen == SWITCHTEC_GEN4)
		part_id = &stdev->mmio_sys_info->gen4.partition_id;
	else
		return -ENOTSUPP;
		return -EOPNOTSUPP;

	stdev->partition = ioread8(part_id);
	stdev->partition_count = ioread8(&stdev->mmio_ntb->partition_count);
+1 −0
Original line number Diff line number Diff line
@@ -19,6 +19,7 @@
#define SWITCHTEC_EVENT_EN_CLI   BIT(2)
#define SWITCHTEC_EVENT_EN_IRQ   BIT(3)
#define SWITCHTEC_EVENT_FATAL    BIT(4)
#define SWITCHTEC_EVENT_NOT_SUPP BIT(31)

#define SWITCHTEC_DMA_MRPC_EN	BIT(0)