Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * Copyright 2018-2020 Broadcom.
0004  */
0005 
0006 #include <linux/tty.h>
0007 #include <linux/tty_driver.h>
0008 #include <linux/tty_flip.h>
0009 
0010 #include "bcm_vk.h"
0011 
0012 /* TTYVK base offset is 0x30000 into BAR1 */
0013 #define BAR1_TTYVK_BASE_OFFSET  0x300000
0014 /* Each TTYVK channel (TO or FROM) is 0x10000 */
0015 #define BAR1_TTYVK_CHAN_OFFSET  0x100000
0016 /* Each TTYVK channel has TO and FROM, hence the * 2 */
0017 #define BAR1_TTYVK_BASE(index)  (BAR1_TTYVK_BASE_OFFSET + \
0018                  ((index) * BAR1_TTYVK_CHAN_OFFSET * 2))
0019 /* TO TTYVK channel base comes before FROM for each index */
0020 #define TO_TTYK_BASE(index) BAR1_TTYVK_BASE(index)
0021 #define FROM_TTYK_BASE(index)   (BAR1_TTYVK_BASE(index) + \
0022                  BAR1_TTYVK_CHAN_OFFSET)
0023 
0024 struct bcm_vk_tty_chan {
0025     u32 reserved;
0026     u32 size;
0027     u32 wr;
0028     u32 rd;
0029     u32 *data;
0030 };
0031 
0032 #define VK_BAR_CHAN(v, DIR, e)  ((v)->DIR##_offset \
0033                  + offsetof(struct bcm_vk_tty_chan, e))
0034 #define VK_BAR_CHAN_SIZE(v, DIR)    VK_BAR_CHAN(v, DIR, size)
0035 #define VK_BAR_CHAN_WR(v, DIR)      VK_BAR_CHAN(v, DIR, wr)
0036 #define VK_BAR_CHAN_RD(v, DIR)      VK_BAR_CHAN(v, DIR, rd)
0037 #define VK_BAR_CHAN_DATA(v, DIR, off)   (VK_BAR_CHAN(v, DIR, data) + (off))
0038 
0039 #define VK_BAR0_REGSEG_TTY_DB_OFFSET    0x86c
0040 
0041 /* Poll every 1/10 of second - temp hack till we use MSI interrupt */
0042 #define SERIAL_TIMER_VALUE (HZ / 10)
0043 
0044 static void bcm_vk_tty_poll(struct timer_list *t)
0045 {
0046     struct bcm_vk *vk = from_timer(vk, t, serial_timer);
0047 
0048     queue_work(vk->tty_wq_thread, &vk->tty_wq_work);
0049     mod_timer(&vk->serial_timer, jiffies + SERIAL_TIMER_VALUE);
0050 }
0051 
0052 irqreturn_t bcm_vk_tty_irqhandler(int irq, void *dev_id)
0053 {
0054     struct bcm_vk *vk = dev_id;
0055 
0056     queue_work(vk->tty_wq_thread, &vk->tty_wq_work);
0057 
0058     return IRQ_HANDLED;
0059 }
0060 
0061 static void bcm_vk_tty_wq_handler(struct work_struct *work)
0062 {
0063     struct bcm_vk *vk = container_of(work, struct bcm_vk, tty_wq_work);
0064     struct bcm_vk_tty *vktty;
0065     int card_status;
0066     int count;
0067     unsigned char c;
0068     int i;
0069     int wr;
0070 
0071     card_status = vkread32(vk, BAR_0, BAR_CARD_STATUS);
0072     if (BCM_VK_INTF_IS_DOWN(card_status))
0073         return;
0074 
0075     for (i = 0; i < BCM_VK_NUM_TTY; i++) {
0076         count = 0;
0077         /* Check the card status that the tty channel is ready */
0078         if ((card_status & BIT(i)) == 0)
0079             continue;
0080 
0081         vktty = &vk->tty[i];
0082 
0083         /* Don't increment read index if tty app is closed */
0084         if (!vktty->is_opened)
0085             continue;
0086 
0087         /* Fetch the wr offset in buffer from VK */
0088         wr = vkread32(vk, BAR_1, VK_BAR_CHAN_WR(vktty, from));
0089 
0090         /* safe to ignore until bar read gives proper size */
0091         if (vktty->from_size == 0)
0092             continue;
0093 
0094         if (wr >= vktty->from_size) {
0095             dev_err(&vk->pdev->dev,
0096                 "ERROR: wq handler ttyVK%d wr:0x%x > 0x%x\n",
0097                 i, wr, vktty->from_size);
0098             /* Need to signal and close device in this case */
0099             continue;
0100         }
0101 
0102         /*
0103          * Simple read of circular buffer and
0104          * insert into tty flip buffer
0105          */
0106         while (vk->tty[i].rd != wr) {
0107             c = vkread8(vk, BAR_1,
0108                     VK_BAR_CHAN_DATA(vktty, from, vktty->rd));
0109             vktty->rd++;
0110             if (vktty->rd >= vktty->from_size)
0111                 vktty->rd = 0;
0112             tty_insert_flip_char(&vktty->port, c, TTY_NORMAL);
0113             count++;
0114         }
0115 
0116         if (count) {
0117             tty_flip_buffer_push(&vktty->port);
0118 
0119             /* Update read offset from shadow register to card */
0120             vkwrite32(vk, vktty->rd, BAR_1,
0121                   VK_BAR_CHAN_RD(vktty, from));
0122         }
0123     }
0124 }
0125 
0126 static int bcm_vk_tty_open(struct tty_struct *tty, struct file *file)
0127 {
0128     int card_status;
0129     struct bcm_vk *vk;
0130     struct bcm_vk_tty *vktty;
0131     int index;
0132 
0133     /* initialize the pointer in case something fails */
0134     tty->driver_data = NULL;
0135 
0136     vk = (struct bcm_vk *)dev_get_drvdata(tty->dev);
0137     index = tty->index;
0138 
0139     if (index >= BCM_VK_NUM_TTY)
0140         return -EINVAL;
0141 
0142     vktty = &vk->tty[index];
0143 
0144     vktty->pid = task_pid_nr(current);
0145     vktty->to_offset = TO_TTYK_BASE(index);
0146     vktty->from_offset = FROM_TTYK_BASE(index);
0147 
0148     /* Do not allow tty device to be opened if tty on card not ready */
0149     card_status = vkread32(vk, BAR_0, BAR_CARD_STATUS);
0150     if (BCM_VK_INTF_IS_DOWN(card_status) || ((card_status & BIT(index)) == 0))
0151         return -EBUSY;
0152 
0153     /*
0154      * Get shadow registers of the buffer sizes and the "to" write offset
0155      * and "from" read offset
0156      */
0157     vktty->to_size = vkread32(vk, BAR_1, VK_BAR_CHAN_SIZE(vktty, to));
0158     vktty->wr = vkread32(vk, BAR_1,  VK_BAR_CHAN_WR(vktty, to));
0159     vktty->from_size = vkread32(vk, BAR_1, VK_BAR_CHAN_SIZE(vktty, from));
0160     vktty->rd = vkread32(vk, BAR_1,  VK_BAR_CHAN_RD(vktty, from));
0161     vktty->is_opened = true;
0162 
0163     if (tty->count == 1 && !vktty->irq_enabled) {
0164         timer_setup(&vk->serial_timer, bcm_vk_tty_poll, 0);
0165         mod_timer(&vk->serial_timer, jiffies + SERIAL_TIMER_VALUE);
0166     }
0167     return 0;
0168 }
0169 
0170 static void bcm_vk_tty_close(struct tty_struct *tty, struct file *file)
0171 {
0172     struct bcm_vk *vk = dev_get_drvdata(tty->dev);
0173 
0174     if (tty->index >= BCM_VK_NUM_TTY)
0175         return;
0176 
0177     vk->tty[tty->index].is_opened = false;
0178 
0179     if (tty->count == 1)
0180         del_timer_sync(&vk->serial_timer);
0181 }
0182 
0183 static void bcm_vk_tty_doorbell(struct bcm_vk *vk, u32 db_val)
0184 {
0185     vkwrite32(vk, db_val, BAR_0,
0186           VK_BAR0_REGSEG_DB_BASE + VK_BAR0_REGSEG_TTY_DB_OFFSET);
0187 }
0188 
0189 static int bcm_vk_tty_write(struct tty_struct *tty,
0190                 const unsigned char *buffer,
0191                 int count)
0192 {
0193     int index;
0194     struct bcm_vk *vk;
0195     struct bcm_vk_tty *vktty;
0196     int i;
0197 
0198     index = tty->index;
0199     vk = dev_get_drvdata(tty->dev);
0200     vktty = &vk->tty[index];
0201 
0202     /* Simple write each byte to circular buffer */
0203     for (i = 0; i < count; i++) {
0204         vkwrite8(vk, buffer[i], BAR_1,
0205              VK_BAR_CHAN_DATA(vktty, to, vktty->wr));
0206         vktty->wr++;
0207         if (vktty->wr >= vktty->to_size)
0208             vktty->wr = 0;
0209     }
0210     /* Update write offset from shadow register to card */
0211     vkwrite32(vk, vktty->wr, BAR_1, VK_BAR_CHAN_WR(vktty, to));
0212     bcm_vk_tty_doorbell(vk, 0);
0213 
0214     return count;
0215 }
0216 
0217 static unsigned int bcm_vk_tty_write_room(struct tty_struct *tty)
0218 {
0219     struct bcm_vk *vk = dev_get_drvdata(tty->dev);
0220 
0221     return vk->tty[tty->index].to_size - 1;
0222 }
0223 
0224 static const struct tty_operations serial_ops = {
0225     .open = bcm_vk_tty_open,
0226     .close = bcm_vk_tty_close,
0227     .write = bcm_vk_tty_write,
0228     .write_room = bcm_vk_tty_write_room,
0229 };
0230 
0231 int bcm_vk_tty_init(struct bcm_vk *vk, char *name)
0232 {
0233     int i;
0234     int err;
0235     struct tty_driver *tty_drv;
0236     struct device *dev = &vk->pdev->dev;
0237 
0238     tty_drv = tty_alloc_driver
0239                 (BCM_VK_NUM_TTY,
0240                  TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV);
0241     if (IS_ERR(tty_drv))
0242         return PTR_ERR(tty_drv);
0243 
0244     /* Save struct tty_driver for uninstalling the device */
0245     vk->tty_drv = tty_drv;
0246 
0247     /* initialize the tty driver */
0248     tty_drv->driver_name = KBUILD_MODNAME;
0249     tty_drv->name = kstrdup(name, GFP_KERNEL);
0250     if (!tty_drv->name) {
0251         err = -ENOMEM;
0252         goto err_tty_driver_kref_put;
0253     }
0254     tty_drv->type = TTY_DRIVER_TYPE_SERIAL;
0255     tty_drv->subtype = SERIAL_TYPE_NORMAL;
0256     tty_drv->init_termios = tty_std_termios;
0257     tty_set_operations(tty_drv, &serial_ops);
0258 
0259     /* register the tty driver */
0260     err = tty_register_driver(tty_drv);
0261     if (err) {
0262         dev_err(dev, "tty_register_driver failed\n");
0263         goto err_kfree_tty_name;
0264     }
0265 
0266     for (i = 0; i < BCM_VK_NUM_TTY; i++) {
0267         struct device *tty_dev;
0268 
0269         tty_port_init(&vk->tty[i].port);
0270         tty_dev = tty_port_register_device_attr(&vk->tty[i].port,
0271                             tty_drv, i, dev, vk,
0272                             NULL);
0273         if (IS_ERR(tty_dev)) {
0274             err = PTR_ERR(tty_dev);
0275             goto unwind;
0276         }
0277         vk->tty[i].is_opened = false;
0278     }
0279 
0280     INIT_WORK(&vk->tty_wq_work, bcm_vk_tty_wq_handler);
0281     vk->tty_wq_thread = create_singlethread_workqueue("tty");
0282     if (!vk->tty_wq_thread) {
0283         dev_err(dev, "Fail to create tty workqueue thread\n");
0284         err = -ENOMEM;
0285         goto unwind;
0286     }
0287     return 0;
0288 
0289 unwind:
0290     while (--i >= 0)
0291         tty_port_unregister_device(&vk->tty[i].port, tty_drv, i);
0292     tty_unregister_driver(tty_drv);
0293 
0294 err_kfree_tty_name:
0295     kfree(tty_drv->name);
0296     tty_drv->name = NULL;
0297 
0298 err_tty_driver_kref_put:
0299     tty_driver_kref_put(tty_drv);
0300 
0301     return err;
0302 }
0303 
0304 void bcm_vk_tty_exit(struct bcm_vk *vk)
0305 {
0306     int i;
0307 
0308     del_timer_sync(&vk->serial_timer);
0309     for (i = 0; i < BCM_VK_NUM_TTY; ++i) {
0310         tty_port_unregister_device(&vk->tty[i].port,
0311                        vk->tty_drv,
0312                        i);
0313         tty_port_destroy(&vk->tty[i].port);
0314     }
0315     tty_unregister_driver(vk->tty_drv);
0316 
0317     kfree(vk->tty_drv->name);
0318     vk->tty_drv->name = NULL;
0319 
0320     tty_driver_kref_put(vk->tty_drv);
0321 }
0322 
0323 void bcm_vk_tty_terminate_tty_user(struct bcm_vk *vk)
0324 {
0325     struct bcm_vk_tty *vktty;
0326     int i;
0327 
0328     for (i = 0; i < BCM_VK_NUM_TTY; ++i) {
0329         vktty = &vk->tty[i];
0330         if (vktty->pid)
0331             kill_pid(find_vpid(vktty->pid), SIGKILL, 1);
0332     }
0333 }
0334 
0335 void bcm_vk_tty_wq_exit(struct bcm_vk *vk)
0336 {
0337     cancel_work_sync(&vk->tty_wq_work);
0338     destroy_workqueue(vk->tty_wq_thread);
0339 }