static int mips_ejtag_fdc_tty_probe()

in mips_ejtag_fdc.c [885:1046]


static int mips_ejtag_fdc_tty_probe(struct mips_cdmm_device *dev)
{
	int ret, nport;
	struct mips_ejtag_fdc_tty_port *dport;
	struct mips_ejtag_fdc_tty *priv;
	struct tty_driver *driver;
	unsigned int cfg, tx_fifo;

	priv = devm_kzalloc(&dev->dev, sizeof(*priv), GFP_KERNEL);
	if (!priv)
		return -ENOMEM;
	priv->cpu = dev->cpu;
	priv->dev = &dev->dev;
	mips_cdmm_set_drvdata(dev, priv);
	atomic_set(&priv->xmit_total, 0);
	raw_spin_lock_init(&priv->lock);

	priv->reg = devm_ioremap(priv->dev, dev->res.start,
					 resource_size(&dev->res));
	if (!priv->reg) {
		dev_err(priv->dev, "ioremap failed for resource %pR\n",
			&dev->res);
		return -ENOMEM;
	}

	cfg = mips_ejtag_fdc_read(priv, REG_FDCFG);
	tx_fifo = (cfg & REG_FDCFG_TXFIFOSIZE) >> REG_FDCFG_TXFIFOSIZE_SHIFT;
	/* Disable interrupts */
	cfg &= ~(REG_FDCFG_TXINTTHRES | REG_FDCFG_RXINTTHRES);
	cfg |= REG_FDCFG_TXINTTHRES_DISABLED;
	cfg |= REG_FDCFG_RXINTTHRES_DISABLED;
	mips_ejtag_fdc_write(priv, REG_FDCFG, cfg);

	/* Make each port's xmit FIFO big enough to fill FDC TX FIFO */
	priv->xmit_size = min(tx_fifo * 4, (unsigned int)SERIAL_XMIT_SIZE);

	driver = tty_alloc_driver(NUM_TTY_CHANNELS, TTY_DRIVER_REAL_RAW);
	if (IS_ERR(driver))
		return PTR_ERR(driver);
	priv->driver = driver;

	driver->driver_name = "ejtag_fdc";
	snprintf(priv->fdc_name, sizeof(priv->fdc_name), "ttyFDC%u", dev->cpu);
	snprintf(priv->driver_name, sizeof(priv->driver_name), "%sc",
		 priv->fdc_name);
	driver->name = priv->driver_name;
	driver->major = 0; /* Auto-allocate */
	driver->minor_start = 0;
	driver->type = TTY_DRIVER_TYPE_SERIAL;
	driver->subtype = SERIAL_TYPE_NORMAL;
	driver->init_termios = tty_std_termios;
	driver->init_termios.c_cflag |= CLOCAL;
	driver->driver_state = priv;

	tty_set_operations(driver, &mips_ejtag_fdc_tty_ops);
	for (nport = 0; nport < NUM_TTY_CHANNELS; nport++) {
		dport = &priv->ports[nport];
		dport->driver = priv;
		tty_port_init(&dport->port);
		dport->port.ops = &mips_ejtag_fdc_tty_port_ops;
		raw_spin_lock_init(&dport->rx_lock);
		spin_lock_init(&dport->xmit_lock);
		/* The xmit buffer starts empty, i.e. completely written */
		init_completion(&dport->xmit_empty);
		complete(&dport->xmit_empty);
	}

	/* Set up the console */
	mips_ejtag_fdc_con.regs[dev->cpu] = priv->reg;
	if (dev->cpu == 0)
		mips_ejtag_fdc_con.tty_drv = driver;

	init_waitqueue_head(&priv->waitqueue);
	/*
	 * Bind the writer thread to the right CPU so it can't migrate.
	 * The channels are per-CPU and we want all channel I/O to be on a
	 * single predictable CPU.
	 */
	priv->thread = kthread_run_on_cpu(mips_ejtag_fdc_put, priv,
					  dev->cpu, "ttyFDC/%u");
	if (IS_ERR(priv->thread)) {
		ret = PTR_ERR(priv->thread);
		dev_err(priv->dev, "Couldn't create kthread (%d)\n", ret);
		goto err_destroy_ports;
	}

	/* Look for an FDC IRQ */
	priv->irq = get_c0_fdc_int();

	/* Try requesting the IRQ */
	if (priv->irq >= 0) {
		/*
		 * IRQF_SHARED, IRQF_COND_SUSPEND: The FDC IRQ may be shared with
		 * other local interrupts such as the timer which sets
		 * IRQF_TIMER (including IRQF_NO_SUSPEND).
		 *
		 * IRQF_NO_THREAD: The FDC IRQ isn't individually maskable so it
		 * cannot be deferred and handled by a thread on RT kernels. For
		 * this reason any spinlocks used from the ISR are raw.
		 */
		ret = devm_request_irq(priv->dev, priv->irq, mips_ejtag_fdc_isr,
				       IRQF_PERCPU | IRQF_SHARED |
				       IRQF_NO_THREAD | IRQF_COND_SUSPEND,
				       priv->fdc_name, priv);
		if (ret)
			priv->irq = -1;
	}
	if (priv->irq >= 0) {
		/* IRQ is usable, enable RX interrupt */
		raw_spin_lock_irq(&priv->lock);
		cfg = mips_ejtag_fdc_read(priv, REG_FDCFG);
		cfg &= ~REG_FDCFG_RXINTTHRES;
		cfg |= REG_FDCFG_RXINTTHRES_NOTEMPTY;
		mips_ejtag_fdc_write(priv, REG_FDCFG, cfg);
		raw_spin_unlock_irq(&priv->lock);
	} else {
		/* If we didn't get an usable IRQ, poll instead */
		timer_setup(&priv->poll_timer, mips_ejtag_fdc_tty_timer,
			    TIMER_PINNED);
		priv->poll_timer.expires = jiffies + FDC_TTY_POLL;
		/*
		 * Always attach the timer to the right CPU. The channels are
		 * per-CPU so all polling should be from a single CPU.
		 */
		add_timer_on(&priv->poll_timer, dev->cpu);

		dev_info(priv->dev, "No usable IRQ, polling enabled\n");
	}

	ret = tty_register_driver(driver);
	if (ret < 0) {
		dev_err(priv->dev, "Couldn't install tty driver (%d)\n", ret);
		goto err_stop_irq;
	}

	return 0;

err_stop_irq:
	if (priv->irq >= 0) {
		raw_spin_lock_irq(&priv->lock);
		cfg = mips_ejtag_fdc_read(priv, REG_FDCFG);
		/* Disable interrupts */
		cfg &= ~(REG_FDCFG_TXINTTHRES | REG_FDCFG_RXINTTHRES);
		cfg |= REG_FDCFG_TXINTTHRES_DISABLED;
		cfg |= REG_FDCFG_RXINTTHRES_DISABLED;
		mips_ejtag_fdc_write(priv, REG_FDCFG, cfg);
		raw_spin_unlock_irq(&priv->lock);
	} else {
		priv->removing = true;
		del_timer_sync(&priv->poll_timer);
	}
	kthread_stop(priv->thread);
err_destroy_ports:
	if (dev->cpu == 0)
		mips_ejtag_fdc_con.tty_drv = NULL;
	for (nport = 0; nport < NUM_TTY_CHANNELS; nport++) {
		dport = &priv->ports[nport];
		tty_port_destroy(&dport->port);
	}
	tty_driver_kref_put(priv->driver);
	return ret;
}