drivers/s390/cio/device_pgid.c

Source file repositories/reference/linux-study-clean/drivers/s390/cio/device_pgid.c

File Facts

System
Linux kernel
Corpus path
drivers/s390/cio/device_pgid.c
Extension
.c
Size
18011 bytes
Lines
728
Domain
Driver Families
Bucket
drivers/s390
Inferred role
Driver Families: implementation source
Status
source implementation candidate

Why This File Exists

Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.

Dependency Surface

Detected Declarations

Annotated Snippet

struct stlck_data {
	struct completion done;
	int rc;
};

static void stlck_build_cp(struct ccw_device *cdev, void *buf1, void *buf2)
{
	struct ccw_request *req = &cdev->private->req;
	struct ccw1 *cp = cdev->private->dma_area->iccws;

	cp[0].cmd_code = CCW_CMD_STLCK;
	cp[0].cda = virt_to_dma32(buf1);
	cp[0].count = 32;
	cp[0].flags = CCW_FLAG_CC;
	cp[1].cmd_code = CCW_CMD_RELEASE;
	cp[1].cda = virt_to_dma32(buf2);
	cp[1].count = 32;
	cp[1].flags = 0;
	req->cp = cp;
}

static void stlck_callback(struct ccw_device *cdev, void *data, int rc)
{
	struct stlck_data *sdata = data;

	sdata->rc = rc;
	complete(&sdata->done);
}

/**
 * ccw_device_stlck_start - perform unconditional release
 * @cdev: ccw device
 * @data: data pointer to be passed to ccw_device_stlck_done
 * @buf1: data pointer used in channel program
 * @buf2: data pointer used in channel program
 *
 * Execute a channel program on @cdev to release an existing PGID reservation.
 */
static void ccw_device_stlck_start(struct ccw_device *cdev, void *data,
				   void *buf1, void *buf2)
{
	struct subchannel *sch = to_subchannel(cdev->dev.parent);
	struct ccw_request *req = &cdev->private->req;

	CIO_TRACE_EVENT(4, "stlck");
	CIO_HEX_EVENT(4, &cdev->private->dev_id, sizeof(cdev->private->dev_id));
	/* Request setup. */
	memset(req, 0, sizeof(*req));
	req->timeout	= PGID_TIMEOUT;
	req->maxretries	= PGID_RETRIES;
	req->lpm	= sch->schib.pmcw.pam & sch->opm;
	req->data	= data;
	req->callback	= stlck_callback;
	stlck_build_cp(cdev, buf1, buf2);
	ccw_request_start(cdev);
}

/*
 * Perform unconditional reserve + release.
 */
int ccw_device_stlck(struct ccw_device *cdev)
{
	struct subchannel *sch = to_subchannel(cdev->dev.parent);
	struct stlck_data data;
	u8 *buffer;
	int rc;

	/* Check if steal lock operation is valid for this device. */
	if (cdev->drv) {
		if (!cdev->private->options.force)
			return -EINVAL;
	}
	buffer = kzalloc(64, GFP_DMA | GFP_KERNEL);
	if (!buffer)
		return -ENOMEM;
	init_completion(&data.done);
	data.rc = -EIO;
	spin_lock_irq(&sch->lock);
	rc = cio_enable_subchannel(sch, (u32)virt_to_phys(sch));
	if (rc)
		goto out_unlock;
	/* Perform operation. */
	cdev->private->state = DEV_STATE_STEAL_LOCK;
	ccw_device_stlck_start(cdev, &data, &buffer[0], &buffer[32]);
	spin_unlock_irq(&sch->lock);
	/* Wait for operation to finish. */
	if (wait_for_completion_interruptible(&data.done)) {
		/* Got a signal. */
		spin_lock_irq(&sch->lock);
		ccw_request_cancel(cdev);

Annotation

Implementation Notes