Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * xhci-dbgtty.c - tty glue for xHCI debug capability
0004  *
0005  * Copyright (C) 2017 Intel Corporation
0006  *
0007  * Author: Lu Baolu <baolu.lu@linux.intel.com>
0008  */
0009 
0010 #include <linux/slab.h>
0011 #include <linux/tty.h>
0012 #include <linux/tty_flip.h>
0013 #include <linux/idr.h>
0014 
0015 #include "xhci.h"
0016 #include "xhci-dbgcap.h"
0017 
0018 static struct tty_driver *dbc_tty_driver;
0019 static struct idr dbc_tty_minors;
0020 static DEFINE_MUTEX(dbc_tty_minors_lock);
0021 
0022 static inline struct dbc_port *dbc_to_port(struct xhci_dbc *dbc)
0023 {
0024     return dbc->priv;
0025 }
0026 
0027 static unsigned int
0028 dbc_send_packet(struct dbc_port *port, char *packet, unsigned int size)
0029 {
0030     unsigned int        len;
0031 
0032     len = kfifo_len(&port->write_fifo);
0033     if (len < size)
0034         size = len;
0035     if (size != 0)
0036         size = kfifo_out(&port->write_fifo, packet, size);
0037     return size;
0038 }
0039 
0040 static int dbc_start_tx(struct dbc_port *port)
0041     __releases(&port->port_lock)
0042     __acquires(&port->port_lock)
0043 {
0044     int         len;
0045     struct dbc_request  *req;
0046     int         status = 0;
0047     bool            do_tty_wake = false;
0048     struct list_head    *pool = &port->write_pool;
0049 
0050     while (!list_empty(pool)) {
0051         req = list_entry(pool->next, struct dbc_request, list_pool);
0052         len = dbc_send_packet(port, req->buf, DBC_MAX_PACKET);
0053         if (len == 0)
0054             break;
0055         do_tty_wake = true;
0056 
0057         req->length = len;
0058         list_del(&req->list_pool);
0059 
0060         spin_unlock(&port->port_lock);
0061         status = dbc_ep_queue(req);
0062         spin_lock(&port->port_lock);
0063 
0064         if (status) {
0065             list_add(&req->list_pool, pool);
0066             break;
0067         }
0068     }
0069 
0070     if (do_tty_wake && port->port.tty)
0071         tty_wakeup(port->port.tty);
0072 
0073     return status;
0074 }
0075 
0076 static void dbc_start_rx(struct dbc_port *port)
0077     __releases(&port->port_lock)
0078     __acquires(&port->port_lock)
0079 {
0080     struct dbc_request  *req;
0081     int         status;
0082     struct list_head    *pool = &port->read_pool;
0083 
0084     while (!list_empty(pool)) {
0085         if (!port->port.tty)
0086             break;
0087 
0088         req = list_entry(pool->next, struct dbc_request, list_pool);
0089         list_del(&req->list_pool);
0090         req->length = DBC_MAX_PACKET;
0091 
0092         spin_unlock(&port->port_lock);
0093         status = dbc_ep_queue(req);
0094         spin_lock(&port->port_lock);
0095 
0096         if (status) {
0097             list_add(&req->list_pool, pool);
0098             break;
0099         }
0100     }
0101 }
0102 
0103 static void
0104 dbc_read_complete(struct xhci_dbc *dbc, struct dbc_request *req)
0105 {
0106     unsigned long       flags;
0107     struct dbc_port     *port = dbc_to_port(dbc);
0108 
0109     spin_lock_irqsave(&port->port_lock, flags);
0110     list_add_tail(&req->list_pool, &port->read_queue);
0111     tasklet_schedule(&port->push);
0112     spin_unlock_irqrestore(&port->port_lock, flags);
0113 }
0114 
0115 static void dbc_write_complete(struct xhci_dbc *dbc, struct dbc_request *req)
0116 {
0117     unsigned long       flags;
0118     struct dbc_port     *port = dbc_to_port(dbc);
0119 
0120     spin_lock_irqsave(&port->port_lock, flags);
0121     list_add(&req->list_pool, &port->write_pool);
0122     switch (req->status) {
0123     case 0:
0124         dbc_start_tx(port);
0125         break;
0126     case -ESHUTDOWN:
0127         break;
0128     default:
0129         dev_warn(dbc->dev, "unexpected write complete status %d\n",
0130               req->status);
0131         break;
0132     }
0133     spin_unlock_irqrestore(&port->port_lock, flags);
0134 }
0135 
0136 static void xhci_dbc_free_req(struct dbc_request *req)
0137 {
0138     kfree(req->buf);
0139     dbc_free_request(req);
0140 }
0141 
0142 static int
0143 xhci_dbc_alloc_requests(struct xhci_dbc *dbc, unsigned int direction,
0144             struct list_head *head,
0145             void (*fn)(struct xhci_dbc *, struct dbc_request *))
0146 {
0147     int         i;
0148     struct dbc_request  *req;
0149 
0150     for (i = 0; i < DBC_QUEUE_SIZE; i++) {
0151         req = dbc_alloc_request(dbc, direction, GFP_KERNEL);
0152         if (!req)
0153             break;
0154 
0155         req->length = DBC_MAX_PACKET;
0156         req->buf = kmalloc(req->length, GFP_KERNEL);
0157         if (!req->buf) {
0158             dbc_free_request(req);
0159             break;
0160         }
0161 
0162         req->complete = fn;
0163         list_add_tail(&req->list_pool, head);
0164     }
0165 
0166     return list_empty(head) ? -ENOMEM : 0;
0167 }
0168 
0169 static void
0170 xhci_dbc_free_requests(struct list_head *head)
0171 {
0172     struct dbc_request  *req;
0173 
0174     while (!list_empty(head)) {
0175         req = list_entry(head->next, struct dbc_request, list_pool);
0176         list_del(&req->list_pool);
0177         xhci_dbc_free_req(req);
0178     }
0179 }
0180 
0181 static int dbc_tty_install(struct tty_driver *driver, struct tty_struct *tty)
0182 {
0183     struct dbc_port     *port;
0184 
0185     mutex_lock(&dbc_tty_minors_lock);
0186     port = idr_find(&dbc_tty_minors, tty->index);
0187     mutex_unlock(&dbc_tty_minors_lock);
0188 
0189     if (!port)
0190         return -ENXIO;
0191 
0192     tty->driver_data = port;
0193 
0194     return tty_port_install(&port->port, driver, tty);
0195 }
0196 
0197 static int dbc_tty_open(struct tty_struct *tty, struct file *file)
0198 {
0199     struct dbc_port     *port = tty->driver_data;
0200 
0201     return tty_port_open(&port->port, tty, file);
0202 }
0203 
0204 static void dbc_tty_close(struct tty_struct *tty, struct file *file)
0205 {
0206     struct dbc_port     *port = tty->driver_data;
0207 
0208     tty_port_close(&port->port, tty, file);
0209 }
0210 
0211 static int dbc_tty_write(struct tty_struct *tty,
0212              const unsigned char *buf,
0213              int count)
0214 {
0215     struct dbc_port     *port = tty->driver_data;
0216     unsigned long       flags;
0217 
0218     spin_lock_irqsave(&port->port_lock, flags);
0219     if (count)
0220         count = kfifo_in(&port->write_fifo, buf, count);
0221     dbc_start_tx(port);
0222     spin_unlock_irqrestore(&port->port_lock, flags);
0223 
0224     return count;
0225 }
0226 
0227 static int dbc_tty_put_char(struct tty_struct *tty, unsigned char ch)
0228 {
0229     struct dbc_port     *port = tty->driver_data;
0230     unsigned long       flags;
0231     int         status;
0232 
0233     spin_lock_irqsave(&port->port_lock, flags);
0234     status = kfifo_put(&port->write_fifo, ch);
0235     spin_unlock_irqrestore(&port->port_lock, flags);
0236 
0237     return status;
0238 }
0239 
0240 static void dbc_tty_flush_chars(struct tty_struct *tty)
0241 {
0242     struct dbc_port     *port = tty->driver_data;
0243     unsigned long       flags;
0244 
0245     spin_lock_irqsave(&port->port_lock, flags);
0246     dbc_start_tx(port);
0247     spin_unlock_irqrestore(&port->port_lock, flags);
0248 }
0249 
0250 static unsigned int dbc_tty_write_room(struct tty_struct *tty)
0251 {
0252     struct dbc_port     *port = tty->driver_data;
0253     unsigned long       flags;
0254     unsigned int        room;
0255 
0256     spin_lock_irqsave(&port->port_lock, flags);
0257     room = kfifo_avail(&port->write_fifo);
0258     spin_unlock_irqrestore(&port->port_lock, flags);
0259 
0260     return room;
0261 }
0262 
0263 static unsigned int dbc_tty_chars_in_buffer(struct tty_struct *tty)
0264 {
0265     struct dbc_port     *port = tty->driver_data;
0266     unsigned long       flags;
0267     unsigned int        chars;
0268 
0269     spin_lock_irqsave(&port->port_lock, flags);
0270     chars = kfifo_len(&port->write_fifo);
0271     spin_unlock_irqrestore(&port->port_lock, flags);
0272 
0273     return chars;
0274 }
0275 
0276 static void dbc_tty_unthrottle(struct tty_struct *tty)
0277 {
0278     struct dbc_port     *port = tty->driver_data;
0279     unsigned long       flags;
0280 
0281     spin_lock_irqsave(&port->port_lock, flags);
0282     tasklet_schedule(&port->push);
0283     spin_unlock_irqrestore(&port->port_lock, flags);
0284 }
0285 
0286 static const struct tty_operations dbc_tty_ops = {
0287     .install        = dbc_tty_install,
0288     .open           = dbc_tty_open,
0289     .close          = dbc_tty_close,
0290     .write          = dbc_tty_write,
0291     .put_char       = dbc_tty_put_char,
0292     .flush_chars        = dbc_tty_flush_chars,
0293     .write_room     = dbc_tty_write_room,
0294     .chars_in_buffer    = dbc_tty_chars_in_buffer,
0295     .unthrottle     = dbc_tty_unthrottle,
0296 };
0297 
0298 static void dbc_rx_push(struct tasklet_struct *t)
0299 {
0300     struct dbc_request  *req;
0301     struct tty_struct   *tty;
0302     unsigned long       flags;
0303     bool            do_push = false;
0304     bool            disconnect = false;
0305     struct dbc_port     *port = from_tasklet(port, t, push);
0306     struct list_head    *queue = &port->read_queue;
0307 
0308     spin_lock_irqsave(&port->port_lock, flags);
0309     tty = port->port.tty;
0310     while (!list_empty(queue)) {
0311         req = list_first_entry(queue, struct dbc_request, list_pool);
0312 
0313         if (tty && tty_throttled(tty))
0314             break;
0315 
0316         switch (req->status) {
0317         case 0:
0318             break;
0319         case -ESHUTDOWN:
0320             disconnect = true;
0321             break;
0322         default:
0323             pr_warn("ttyDBC0: unexpected RX status %d\n",
0324                 req->status);
0325             break;
0326         }
0327 
0328         if (req->actual) {
0329             char        *packet = req->buf;
0330             unsigned int    n, size = req->actual;
0331             int     count;
0332 
0333             n = port->n_read;
0334             if (n) {
0335                 packet += n;
0336                 size -= n;
0337             }
0338 
0339             count = tty_insert_flip_string(&port->port, packet,
0340                                size);
0341             if (count)
0342                 do_push = true;
0343             if (count != size) {
0344                 port->n_read += count;
0345                 break;
0346             }
0347             port->n_read = 0;
0348         }
0349 
0350         list_move(&req->list_pool, &port->read_pool);
0351     }
0352 
0353     if (do_push)
0354         tty_flip_buffer_push(&port->port);
0355 
0356     if (!list_empty(queue) && tty) {
0357         if (!tty_throttled(tty)) {
0358             if (do_push)
0359                 tasklet_schedule(&port->push);
0360             else
0361                 pr_warn("ttyDBC0: RX not scheduled?\n");
0362         }
0363     }
0364 
0365     if (!disconnect)
0366         dbc_start_rx(port);
0367 
0368     spin_unlock_irqrestore(&port->port_lock, flags);
0369 }
0370 
0371 static int dbc_port_activate(struct tty_port *_port, struct tty_struct *tty)
0372 {
0373     unsigned long   flags;
0374     struct dbc_port *port = container_of(_port, struct dbc_port, port);
0375 
0376     spin_lock_irqsave(&port->port_lock, flags);
0377     dbc_start_rx(port);
0378     spin_unlock_irqrestore(&port->port_lock, flags);
0379 
0380     return 0;
0381 }
0382 
0383 static const struct tty_port_operations dbc_port_ops = {
0384     .activate = dbc_port_activate,
0385 };
0386 
0387 static void
0388 xhci_dbc_tty_init_port(struct xhci_dbc *dbc, struct dbc_port *port)
0389 {
0390     tty_port_init(&port->port);
0391     spin_lock_init(&port->port_lock);
0392     tasklet_setup(&port->push, dbc_rx_push);
0393     INIT_LIST_HEAD(&port->read_pool);
0394     INIT_LIST_HEAD(&port->read_queue);
0395     INIT_LIST_HEAD(&port->write_pool);
0396 
0397     port->port.ops =    &dbc_port_ops;
0398     port->n_read =      0;
0399 }
0400 
0401 static void
0402 xhci_dbc_tty_exit_port(struct dbc_port *port)
0403 {
0404     tasklet_kill(&port->push);
0405     tty_port_destroy(&port->port);
0406 }
0407 
0408 static int xhci_dbc_tty_register_device(struct xhci_dbc *dbc)
0409 {
0410     int         ret;
0411     struct device       *tty_dev;
0412     struct dbc_port     *port = dbc_to_port(dbc);
0413 
0414     if (port->registered)
0415         return -EBUSY;
0416 
0417     xhci_dbc_tty_init_port(dbc, port);
0418 
0419     mutex_lock(&dbc_tty_minors_lock);
0420     port->minor = idr_alloc(&dbc_tty_minors, port, 0, 64, GFP_KERNEL);
0421     mutex_unlock(&dbc_tty_minors_lock);
0422 
0423     if (port->minor < 0) {
0424         ret = port->minor;
0425         goto err_idr;
0426     }
0427 
0428     ret = kfifo_alloc(&port->write_fifo, DBC_WRITE_BUF_SIZE, GFP_KERNEL);
0429     if (ret)
0430         goto err_exit_port;
0431 
0432     ret = xhci_dbc_alloc_requests(dbc, BULK_IN, &port->read_pool,
0433                       dbc_read_complete);
0434     if (ret)
0435         goto err_free_fifo;
0436 
0437     ret = xhci_dbc_alloc_requests(dbc, BULK_OUT, &port->write_pool,
0438                       dbc_write_complete);
0439     if (ret)
0440         goto err_free_requests;
0441 
0442     tty_dev = tty_port_register_device(&port->port,
0443                        dbc_tty_driver, port->minor, NULL);
0444     if (IS_ERR(tty_dev)) {
0445         ret = PTR_ERR(tty_dev);
0446         goto err_free_requests;
0447     }
0448 
0449     port->registered = true;
0450 
0451     return 0;
0452 
0453 err_free_requests:
0454     xhci_dbc_free_requests(&port->read_pool);
0455     xhci_dbc_free_requests(&port->write_pool);
0456 err_free_fifo:
0457     kfifo_free(&port->write_fifo);
0458 err_exit_port:
0459     idr_remove(&dbc_tty_minors, port->minor);
0460 err_idr:
0461     xhci_dbc_tty_exit_port(port);
0462 
0463     dev_err(dbc->dev, "can't register tty port, err %d\n", ret);
0464 
0465     return ret;
0466 }
0467 
0468 static void xhci_dbc_tty_unregister_device(struct xhci_dbc *dbc)
0469 {
0470     struct dbc_port     *port = dbc_to_port(dbc);
0471 
0472     if (!port->registered)
0473         return;
0474     tty_unregister_device(dbc_tty_driver, port->minor);
0475     xhci_dbc_tty_exit_port(port);
0476     port->registered = false;
0477 
0478     mutex_lock(&dbc_tty_minors_lock);
0479     idr_remove(&dbc_tty_minors, port->minor);
0480     mutex_unlock(&dbc_tty_minors_lock);
0481 
0482     kfifo_free(&port->write_fifo);
0483     xhci_dbc_free_requests(&port->read_pool);
0484     xhci_dbc_free_requests(&port->read_queue);
0485     xhci_dbc_free_requests(&port->write_pool);
0486 }
0487 
0488 static const struct dbc_driver dbc_driver = {
0489     .configure      = xhci_dbc_tty_register_device,
0490     .disconnect     = xhci_dbc_tty_unregister_device,
0491 };
0492 
0493 int xhci_dbc_tty_probe(struct device *dev, void __iomem *base, struct xhci_hcd *xhci)
0494 {
0495     struct xhci_dbc     *dbc;
0496     struct dbc_port     *port;
0497     int         status;
0498 
0499     if (!dbc_tty_driver)
0500         return -ENODEV;
0501 
0502     port = kzalloc(sizeof(*port), GFP_KERNEL);
0503     if (!port)
0504         return -ENOMEM;
0505 
0506     dbc = xhci_alloc_dbc(dev, base, &dbc_driver);
0507 
0508     if (!dbc) {
0509         status = -ENOMEM;
0510         goto out2;
0511     }
0512 
0513     dbc->priv = port;
0514 
0515     /* get rid of xhci once this is a real driver binding to a device */
0516     xhci->dbc = dbc;
0517 
0518     return 0;
0519 out2:
0520     kfree(port);
0521 
0522     return status;
0523 }
0524 
0525 /*
0526  * undo what probe did, assume dbc is stopped already.
0527  * we also assume tty_unregister_device() is called before this
0528  */
0529 void xhci_dbc_tty_remove(struct xhci_dbc *dbc)
0530 {
0531     struct dbc_port         *port = dbc_to_port(dbc);
0532 
0533     xhci_dbc_remove(dbc);
0534     kfree(port);
0535 }
0536 
0537 int dbc_tty_init(void)
0538 {
0539     int     ret;
0540 
0541     idr_init(&dbc_tty_minors);
0542 
0543     dbc_tty_driver = tty_alloc_driver(64, TTY_DRIVER_REAL_RAW |
0544                       TTY_DRIVER_DYNAMIC_DEV);
0545     if (IS_ERR(dbc_tty_driver)) {
0546         idr_destroy(&dbc_tty_minors);
0547         return PTR_ERR(dbc_tty_driver);
0548     }
0549 
0550     dbc_tty_driver->driver_name = "dbc_serial";
0551     dbc_tty_driver->name = "ttyDBC";
0552 
0553     dbc_tty_driver->type = TTY_DRIVER_TYPE_SERIAL;
0554     dbc_tty_driver->subtype = SERIAL_TYPE_NORMAL;
0555     dbc_tty_driver->init_termios = tty_std_termios;
0556     dbc_tty_driver->init_termios.c_cflag =
0557             B9600 | CS8 | CREAD | HUPCL | CLOCAL;
0558     dbc_tty_driver->init_termios.c_ispeed = 9600;
0559     dbc_tty_driver->init_termios.c_ospeed = 9600;
0560 
0561     tty_set_operations(dbc_tty_driver, &dbc_tty_ops);
0562 
0563     ret = tty_register_driver(dbc_tty_driver);
0564     if (ret) {
0565         pr_err("Can't register dbc tty driver\n");
0566         tty_driver_kref_put(dbc_tty_driver);
0567         idr_destroy(&dbc_tty_minors);
0568     }
0569 
0570     return ret;
0571 }
0572 
0573 void dbc_tty_exit(void)
0574 {
0575     if (dbc_tty_driver) {
0576         tty_unregister_driver(dbc_tty_driver);
0577         tty_driver_kref_put(dbc_tty_driver);
0578         dbc_tty_driver = NULL;
0579     }
0580 
0581     idr_destroy(&dbc_tty_minors);
0582 }