Skip to content

Commit

Permalink
misc: bcm-vk: add ttyVK support
Browse files Browse the repository at this point in the history
Add ttyVK support to driver to allow console access to VK card from host.

Device node will be in the follow form /dev/bcm-vk.x_ttyVKy where:
x is the instance of the VK card
y is the tty device number on the VK card

Acked-by: Olof Johansson <olof@lixom.net>
Signed-off-by: Scott Branden <scott.branden@broadcom.com>
Link: https://lore.kernel.org/r/20210120175827.14820-14-scott.branden@broadcom.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
  • Loading branch information
Scott Branden authored and Greg Kroah-Hartman committed Jan 25, 2021
1 parent 68f1fae commit 91ca10d
Show file tree
Hide file tree
Showing 4 changed files with 392 additions and 2 deletions.
3 changes: 2 additions & 1 deletion drivers/misc/bcm-vk/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,6 @@ obj-$(CONFIG_BCM_VK) += bcm_vk.o
bcm_vk-objs := \
bcm_vk_dev.o \
bcm_vk_msg.o \
bcm_vk_sg.o
bcm_vk_sg.o \
bcm_vk_tty.o

28 changes: 28 additions & 0 deletions drivers/misc/bcm-vk/bcm_vk.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,14 @@

#include <linux/atomic.h>
#include <linux/firmware.h>
#include <linux/irq.h>
#include <linux/kref.h>
#include <linux/miscdevice.h>
#include <linux/mutex.h>
#include <linux/pci.h>
#include <linux/poll.h>
#include <linux/sched/signal.h>
#include <linux/tty.h>
#include <linux/uaccess.h>
#include <uapi/linux/misc/bcm_vk.h>

Expand Down Expand Up @@ -84,6 +86,9 @@
#define CODEPUSH_BOOT2_ENTRY 0x60000000

#define BAR_CARD_STATUS 0x410
/* CARD_STATUS definitions */
#define CARD_STATUS_TTYVK0_READY BIT(0)
#define CARD_STATUS_TTYVK1_READY BIT(1)

#define BAR_BOOT1_STDALONE_PROGRESS 0x420
#define BOOT1_STDALONE_SUCCESS (BIT(13) | BIT(14))
Expand Down Expand Up @@ -255,6 +260,19 @@ enum pci_barno {

#define BCM_VK_NUM_TTY 2

struct bcm_vk_tty {
struct tty_port port;
u32 to_offset; /* bar offset to use */
u32 to_size; /* to VK buffer size */
u32 wr; /* write offset shadow */
u32 from_offset; /* bar offset to use */
u32 from_size; /* from VK buffer size */
u32 rd; /* read offset shadow */
pid_t pid;
bool irq_enabled;
bool is_opened; /* tracks tty open/close */
};

/* VK device max power state, supports 3, full, reduced and low */
#define MAX_OPP 3
#define MAX_CARD_INFO_TAG_SIZE 64
Expand Down Expand Up @@ -348,6 +366,12 @@ struct bcm_vk {
struct miscdevice miscdev;
int devid; /* dev id allocated */

struct tty_driver *tty_drv;
struct timer_list serial_timer;
struct bcm_vk_tty tty[BCM_VK_NUM_TTY];
struct workqueue_struct *tty_wq_thread;
struct work_struct tty_wq_work;

/* Reference-counting to handle file operations */
struct kref kref;

Expand Down Expand Up @@ -466,6 +490,7 @@ int bcm_vk_release(struct inode *inode, struct file *p_file);
void bcm_vk_release_data(struct kref *kref);
irqreturn_t bcm_vk_msgq_irqhandler(int irq, void *dev_id);
irqreturn_t bcm_vk_notf_irqhandler(int irq, void *dev_id);
irqreturn_t bcm_vk_tty_irqhandler(int irq, void *dev_id);
int bcm_vk_msg_init(struct bcm_vk *vk);
void bcm_vk_msg_remove(struct bcm_vk *vk);
void bcm_vk_drain_msg_on_reset(struct bcm_vk *vk);
Expand All @@ -476,6 +501,9 @@ int bcm_vk_send_shutdown_msg(struct bcm_vk *vk, u32 shut_type,
const pid_t pid, const u32 q_num);
void bcm_to_v_q_doorbell(struct bcm_vk *vk, u32 q_num, u32 db_val);
int bcm_vk_auto_load_all_images(struct bcm_vk *vk);
int bcm_vk_tty_init(struct bcm_vk *vk, char *name);
void bcm_vk_tty_exit(struct bcm_vk *vk);
void bcm_vk_tty_terminate_tty_user(struct bcm_vk *vk);
void bcm_vk_hb_init(struct bcm_vk *vk);
void bcm_vk_hb_deinit(struct bcm_vk *vk);
void bcm_vk_handle_notf(struct bcm_vk *vk);
Expand Down
30 changes: 29 additions & 1 deletion drivers/misc/bcm-vk/bcm_vk_dev.c
Original file line number Diff line number Diff line change
Expand Up @@ -525,6 +525,7 @@ void bcm_vk_blk_drv_access(struct bcm_vk *vk)
}
}
}
bcm_vk_tty_terminate_tty_user(vk);
spin_unlock(&vk->ctx_lock);
}

Expand Down Expand Up @@ -1384,6 +1385,20 @@ static int bcm_vk_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
}
vk->num_irqs++;

for (i = 0;
(i < VK_MSIX_TTY_MAX) && (vk->num_irqs < irq);
i++, vk->num_irqs++) {
err = devm_request_irq(dev, pci_irq_vector(pdev, vk->num_irqs),
bcm_vk_tty_irqhandler,
IRQF_SHARED, DRV_MODULE_NAME, vk);
if (err) {
dev_err(dev, "failed request tty IRQ %d for MSIX %d\n",
pdev->irq + vk->num_irqs, vk->num_irqs + 1);
goto err_irq;
}
vk->tty[i].irq_enabled = true;
}

id = ida_simple_get(&bcm_vk_ida, 0, 0, GFP_KERNEL);
if (id < 0) {
err = id;
Expand Down Expand Up @@ -1436,6 +1451,11 @@ static int bcm_vk_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
goto err_destroy_workqueue;
}

snprintf(name, sizeof(name), KBUILD_MODNAME ".%d_ttyVK", id);
err = bcm_vk_tty_init(vk, name);
if (err)
goto err_unregister_panic_notifier;

/*
* lets trigger an auto download. We don't want to do it serially here
* because at probing time, it is not supposed to block for a long time.
Expand All @@ -1444,7 +1464,7 @@ static int bcm_vk_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
if (auto_load) {
if ((boot_status & BOOT_STATE_MASK) == BROM_RUNNING) {
if (bcm_vk_trigger_autoload(vk))
goto err_unregister_panic_notifier;
goto err_bcm_vk_tty_exit;
} else {
dev_err(dev,
"Auto-load skipped - BROM not in proper state (0x%x)\n",
Expand All @@ -1459,6 +1479,9 @@ static int bcm_vk_probe(struct pci_dev *pdev, const struct pci_device_id *ent)

return 0;

err_bcm_vk_tty_exit:
bcm_vk_tty_exit(vk);

err_unregister_panic_notifier:
atomic_notifier_chain_unregister(&panic_notifier_list,
&vk->panic_nb);
Expand Down Expand Up @@ -1536,6 +1559,9 @@ static void bcm_vk_remove(struct pci_dev *pdev)
atomic_notifier_chain_unregister(&panic_notifier_list,
&vk->panic_nb);

bcm_vk_msg_remove(vk);
bcm_vk_tty_exit(vk);

if (vk->tdma_vaddr)
dma_free_coherent(&pdev->dev, nr_scratch_pages * PAGE_SIZE,
vk->tdma_vaddr, vk->tdma_addr);
Expand All @@ -1554,6 +1580,8 @@ static void bcm_vk_remove(struct pci_dev *pdev)

cancel_work_sync(&vk->wq_work);
destroy_workqueue(vk->wq_thread);
cancel_work_sync(&vk->tty_wq_work);
destroy_workqueue(vk->tty_wq_thread);

for (i = 0; i < MAX_BAR; i++) {
if (vk->bar[i])
Expand Down
Loading

0 comments on commit 91ca10d

Please sign in to comment.