static ssize_t tsi148_master_write()

in bridges/vme_tsi148.c [1259:1354]


static ssize_t tsi148_master_write(struct vme_master_resource *image, void *buf,
	size_t count, loff_t offset)
{
	int retval = 0, enabled;
	unsigned long long vme_base, size;
	u32 aspace, cycle, dwidth;
	void __iomem *addr = image->kern_base + offset;
	unsigned int done = 0;
	unsigned int count32;

	struct vme_error_handler *handler = NULL;
	struct vme_bridge *tsi148_bridge;
	struct tsi148_driver *bridge;

	tsi148_bridge = image->parent;

	bridge = tsi148_bridge->driver_priv;

	spin_lock(&image->lock);

	if (err_chk) {
		__tsi148_master_get(image, &enabled, &vme_base, &size, &aspace,
				    &cycle, &dwidth);
		handler = vme_register_error_handler(tsi148_bridge, aspace,
						     vme_base + offset, count);
		if (!handler) {
			spin_unlock(&image->lock);
			return -ENOMEM;
		}
	}

	/* Here we apply for the same strategy we do in master_read
	 * function in order to assure the correct cycles.
	 */
	if ((uintptr_t)addr & 0x1) {
		iowrite8(*(u8 *)buf, addr);
		done += 1;
		if (done == count)
			goto out;
	}
	if ((uintptr_t)(addr + done) & 0x2) {
		if ((count - done) < 2) {
			iowrite8(*(u8 *)(buf + done), addr + done);
			done += 1;
			goto out;
		} else {
			iowrite16(*(u16 *)(buf + done), addr + done);
			done += 2;
		}
	}

	count32 = (count - done) & ~0x3;
	while (done < count32) {
		iowrite32(*(u32 *)(buf + done), addr + done);
		done += 4;
	}

	if ((count - done) & 0x2) {
		iowrite16(*(u16 *)(buf + done), addr + done);
		done += 2;
	}
	if ((count - done) & 0x1) {
		iowrite8(*(u8 *)(buf + done), addr + done);
		done += 1;
	}

out:
	retval = count;

	/*
	 * Writes are posted. We need to do a read on the VME bus to flush out
	 * all of the writes before we check for errors. We can't guarantee
	 * that reading the data we have just written is safe. It is believed
	 * that there isn't any read, write re-ordering, so we can read any
	 * location in VME space, so lets read the Device ID from the tsi148's
	 * own registers as mapped into CR/CSR space.
	 *
	 * We check for saved errors in the written address range/space.
	 */

	if (err_chk) {
		ioread16(bridge->flush_image->kern_base + 0x7F000);

		if (handler->num_errors) {
			dev_warn(tsi148_bridge->parent,
				 "First VME write error detected an at address 0x%llx\n",
				 handler->first_error);
			retval = handler->first_error - (vme_base + offset);
		}
		vme_unregister_error_handler(handler);
	}

	spin_unlock(&image->lock);

	return retval;
}