linux/drivers/misc/ibmasm/module.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-or-later
   2
   3/*
   4 * IBM ASM Service Processor Device Driver
   5 *
   6 * Copyright (C) IBM Corporation, 2004
   7 *
   8 * Author: Max Asböck <amax@us.ibm.com>
   9 *
  10 * This driver is based on code originally written by Pete Reynolds
  11 * and others.
  12 */
  13
  14/*
  15 * The ASM device driver does the following things:
  16 *
  17 * 1) When loaded it sends a message to the service processor,
  18 * indicating that an OS is * running. This causes the service processor
  19 * to send periodic heartbeats to the OS.
  20 *
  21 * 2) Answers the periodic heartbeats sent by the service processor.
  22 * Failure to do so would result in system reboot.
  23 *
  24 * 3) Acts as a pass through for dot commands sent from user applications.
  25 * The interface for this is the ibmasmfs file system.
  26 *
  27 * 4) Allows user applications to register for event notification. Events
  28 * are sent to the driver through interrupts. They can be read from user
  29 * space through the ibmasmfs file system.
  30 *
  31 * 5) Allows user space applications to send heartbeats to the service
  32 * processor (aka reverse heartbeats). Again this happens through ibmasmfs.
  33 *
  34 * 6) Handles remote mouse and keyboard event interrupts and makes them
  35 * available to user applications through ibmasmfs.
  36 *
  37 */
  38
  39#include <linux/pci.h>
  40#include <linux/init.h>
  41#include <linux/slab.h>
  42#include "ibmasm.h"
  43#include "lowlevel.h"
  44#include "remote.h"
  45
  46int ibmasm_debug = 0;
  47module_param(ibmasm_debug, int , S_IRUGO | S_IWUSR);
  48MODULE_PARM_DESC(ibmasm_debug, " Set debug mode on or off");
  49
  50
  51static int ibmasm_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
  52{
  53        int result;
  54        struct service_processor *sp;
  55
  56        if ((result = pci_enable_device(pdev))) {
  57                dev_err(&pdev->dev, "Failed to enable PCI device\n");
  58                return result;
  59        }
  60        if ((result = pci_request_regions(pdev, DRIVER_NAME))) {
  61                dev_err(&pdev->dev, "Failed to allocate PCI resources\n");
  62                goto error_resources;
  63        }
  64        /* vnc client won't work without bus-mastering */
  65        pci_set_master(pdev);
  66
  67        sp = kzalloc(sizeof(struct service_processor), GFP_KERNEL);
  68        if (sp == NULL) {
  69                dev_err(&pdev->dev, "Failed to allocate memory\n");
  70                result = -ENOMEM;
  71                goto error_kmalloc;
  72        }
  73
  74        spin_lock_init(&sp->lock);
  75        INIT_LIST_HEAD(&sp->command_queue);
  76
  77        pci_set_drvdata(pdev, (void *)sp);
  78        sp->dev = &pdev->dev;
  79        sp->number = pdev->bus->number;
  80        snprintf(sp->dirname, IBMASM_NAME_SIZE, "%d", sp->number);
  81        snprintf(sp->devname, IBMASM_NAME_SIZE, "%s%d", DRIVER_NAME, sp->number);
  82
  83        result = ibmasm_event_buffer_init(sp);
  84        if (result) {
  85                dev_err(sp->dev, "Failed to allocate event buffer\n");
  86                goto error_eventbuffer;
  87        }
  88
  89        result = ibmasm_heartbeat_init(sp);
  90        if (result) {
  91                dev_err(sp->dev, "Failed to allocate heartbeat command\n");
  92                goto error_heartbeat;
  93        }
  94
  95        sp->irq = pdev->irq;
  96        sp->base_address = pci_ioremap_bar(pdev, 0);
  97        if (!sp->base_address) {
  98                dev_err(sp->dev, "Failed to ioremap pci memory\n");
  99                result =  -ENODEV;
 100                goto error_ioremap;
 101        }
 102
 103        result = request_irq(sp->irq, ibmasm_interrupt_handler, IRQF_SHARED, sp->devname, (void*)sp);
 104        if (result) {
 105                dev_err(sp->dev, "Failed to register interrupt handler\n");
 106                goto error_request_irq;
 107        }
 108
 109        enable_sp_interrupts(sp->base_address);
 110
 111        result = ibmasm_init_remote_input_dev(sp);
 112        if (result) {
 113                dev_err(sp->dev, "Failed to initialize remote queue\n");
 114                goto error_init_remote;
 115        }
 116
 117        result = ibmasm_send_driver_vpd(sp);
 118        if (result) {
 119                dev_err(sp->dev, "Failed to send driver VPD to service processor\n");
 120                goto error_send_message;
 121        }
 122        result = ibmasm_send_os_state(sp, SYSTEM_STATE_OS_UP);
 123        if (result) {
 124                dev_err(sp->dev, "Failed to send OS state to service processor\n");
 125                goto error_send_message;
 126        }
 127        ibmasmfs_add_sp(sp);
 128
 129        ibmasm_register_uart(sp);
 130
 131        return 0;
 132
 133error_send_message:
 134        ibmasm_free_remote_input_dev(sp);
 135error_init_remote:
 136        disable_sp_interrupts(sp->base_address);
 137        free_irq(sp->irq, (void *)sp);
 138error_request_irq:
 139        iounmap(sp->base_address);
 140error_ioremap:
 141        ibmasm_heartbeat_exit(sp);
 142error_heartbeat:
 143        ibmasm_event_buffer_exit(sp);
 144error_eventbuffer:
 145        kfree(sp);
 146error_kmalloc:
 147        pci_release_regions(pdev);
 148error_resources:
 149        pci_disable_device(pdev);
 150
 151        return result;
 152}
 153
 154static void ibmasm_remove_one(struct pci_dev *pdev)
 155{
 156        struct service_processor *sp = pci_get_drvdata(pdev);
 157
 158        dbg("Unregistering UART\n");
 159        ibmasm_unregister_uart(sp);
 160        dbg("Sending OS down message\n");
 161        if (ibmasm_send_os_state(sp, SYSTEM_STATE_OS_DOWN))
 162                err("failed to get response to 'Send OS State' command\n");
 163        dbg("Disabling heartbeats\n");
 164        ibmasm_heartbeat_exit(sp);
 165        dbg("Disabling interrupts\n");
 166        disable_sp_interrupts(sp->base_address);
 167        dbg("Freeing SP irq\n");
 168        free_irq(sp->irq, (void *)sp);
 169        dbg("Cleaning up\n");
 170        ibmasm_free_remote_input_dev(sp);
 171        iounmap(sp->base_address);
 172        ibmasm_event_buffer_exit(sp);
 173        kfree(sp);
 174        pci_release_regions(pdev);
 175        pci_disable_device(pdev);
 176}
 177
 178static struct pci_device_id ibmasm_pci_table[] =
 179{
 180        { PCI_DEVICE(VENDORID_IBM, DEVICEID_RSA) },
 181        {},
 182};
 183
 184static struct pci_driver ibmasm_driver = {
 185        .name           = DRIVER_NAME,
 186        .id_table       = ibmasm_pci_table,
 187        .probe          = ibmasm_init_one,
 188        .remove         = ibmasm_remove_one,
 189};
 190
 191static void __exit ibmasm_exit (void)
 192{
 193        ibmasm_unregister_panic_notifier();
 194        ibmasmfs_unregister();
 195        pci_unregister_driver(&ibmasm_driver);
 196        info(DRIVER_DESC " version " DRIVER_VERSION " unloaded");
 197}
 198
 199static int __init ibmasm_init(void)
 200{
 201        int result = pci_register_driver(&ibmasm_driver);
 202        if (result)
 203                return result;
 204
 205        result = ibmasmfs_register();
 206        if (result) {
 207                pci_unregister_driver(&ibmasm_driver);
 208                err("Failed to register ibmasmfs file system");
 209                return result;
 210        }
 211
 212        ibmasm_register_panic_notifier();
 213        info(DRIVER_DESC " version " DRIVER_VERSION " loaded");
 214        return 0;
 215}
 216
 217module_init(ibmasm_init);
 218module_exit(ibmasm_exit);
 219
 220MODULE_AUTHOR(DRIVER_AUTHOR);
 221MODULE_DESCRIPTION(DRIVER_DESC);
 222MODULE_LICENSE("GPL");
 223MODULE_DEVICE_TABLE(pci, ibmasm_pci_table);
 224
 225