linux/arch/powerpc/platforms/iseries/viopath.c
<<
>>
Prefs
   1/* -*- linux-c -*-
   2 *
   3 *  iSeries Virtual I/O Message Path code
   4 *
   5 *  Authors: Dave Boutcher <boutcher@us.ibm.com>
   6 *           Ryan Arnold <ryanarn@us.ibm.com>
   7 *           Colin Devilbiss <devilbis@us.ibm.com>
   8 *
   9 * (C) Copyright 2000-2005 IBM Corporation
  10 *
  11 * This code is used by the iSeries virtual disk, cd,
  12 * tape, and console to communicate with OS/400 in another
  13 * partition.
  14 *
  15 * This program is free software;  you can redistribute it and/or
  16 * modify it under the terms of the GNU General Public License as
  17 * published by the Free Software Foundation; either version 2 of the
  18 * License, or (at your option) anyu later version.
  19 *
  20 * This program is distributed in the hope that it will be useful, but
  21 * WITHOUT ANY WARRANTY; without even the implied warranty of
  22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  23 * General Public License for more details.
  24 *
  25 * You should have received a copy of the GNU General Public License
  26 * along with this program; if not, write to the Free Software Foundation,
  27 * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  28 *
  29 */
  30#include <linux/module.h>
  31#include <linux/kernel.h>
  32#include <linux/errno.h>
  33#include <linux/vmalloc.h>
  34#include <linux/string.h>
  35#include <linux/proc_fs.h>
  36#include <linux/dma-mapping.h>
  37#include <linux/wait.h>
  38#include <linux/seq_file.h>
  39#include <linux/interrupt.h>
  40#include <linux/completion.h>
  41
  42#include <asm/system.h>
  43#include <asm/uaccess.h>
  44#include <asm/prom.h>
  45#include <asm/firmware.h>
  46#include <asm/iseries/hv_types.h>
  47#include <asm/iseries/hv_lp_event.h>
  48#include <asm/iseries/hv_lp_config.h>
  49#include <asm/iseries/mf.h>
  50#include <asm/iseries/vio.h>
  51
  52/* Status of the path to each other partition in the system.
  53 * This is overkill, since we will only ever establish connections
  54 * to our hosting partition and the primary partition on the system.
  55 * But this allows for other support in the future.
  56 */
  57static struct viopathStatus {
  58        int isOpen;             /* Did we open the path?            */
  59        int isActive;           /* Do we have a mon msg outstanding */
  60        int users[VIO_MAX_SUBTYPES];
  61        HvLpInstanceId mSourceInst;
  62        HvLpInstanceId mTargetInst;
  63        int numberAllocated;
  64} viopathStatus[HVMAXARCHITECTEDLPS];
  65
  66static DEFINE_SPINLOCK(statuslock);
  67
  68/*
  69 * For each kind of event we allocate a buffer that is
  70 * guaranteed not to cross a page boundary
  71 */
  72static unsigned char event_buffer[VIO_MAX_SUBTYPES * 256]
  73        __attribute__((__aligned__(4096)));
  74static atomic_t event_buffer_available[VIO_MAX_SUBTYPES];
  75static int event_buffer_initialised;
  76
  77static void handleMonitorEvent(struct HvLpEvent *event);
  78
  79/*
  80 * We use this structure to handle asynchronous responses.  The caller
  81 * blocks on the semaphore and the handler posts the semaphore.  However,
  82 * if system_state is not SYSTEM_RUNNING, then wait_atomic is used ...
  83 */
  84struct alloc_parms {
  85        struct completion done;
  86        int number;
  87        atomic_t wait_atomic;
  88        int used_wait_atomic;
  89};
  90
  91/* Put a sequence number in each mon msg.  The value is not
  92 * important.  Start at something other than 0 just for
  93 * readability.  wrapping this is ok.
  94 */
  95static u8 viomonseq = 22;
  96
  97/* Our hosting logical partition.  We get this at startup
  98 * time, and different modules access this variable directly.
  99 */
 100HvLpIndex viopath_hostLp = HvLpIndexInvalid;
 101EXPORT_SYMBOL(viopath_hostLp);
 102HvLpIndex viopath_ourLp = HvLpIndexInvalid;
 103EXPORT_SYMBOL(viopath_ourLp);
 104
 105/* For each kind of incoming event we set a pointer to a
 106 * routine to call.
 107 */
 108static vio_event_handler_t *vio_handler[VIO_MAX_SUBTYPES];
 109
 110#define VIOPATH_KERN_WARN       KERN_WARNING "viopath: "
 111#define VIOPATH_KERN_INFO       KERN_INFO "viopath: "
 112
 113static int proc_viopath_show(struct seq_file *m, void *v)
 114{
 115        char *buf;
 116        u16 vlanMap;
 117        dma_addr_t handle;
 118        HvLpEvent_Rc hvrc;
 119        DECLARE_COMPLETION(done);
 120        struct device_node *node;
 121        const char *sysid;
 122
 123        buf = kzalloc(HW_PAGE_SIZE, GFP_KERNEL);
 124        if (!buf)
 125                return 0;
 126
 127        handle = iseries_hv_map(buf, HW_PAGE_SIZE, DMA_FROM_DEVICE);
 128
 129        hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp,
 130                        HvLpEvent_Type_VirtualIo,
 131                        viomajorsubtype_config | vioconfigget,
 132                        HvLpEvent_AckInd_DoAck, HvLpEvent_AckType_ImmediateAck,
 133                        viopath_sourceinst(viopath_hostLp),
 134                        viopath_targetinst(viopath_hostLp),
 135                        (u64)(unsigned long)&done, VIOVERSION << 16,
 136                        ((u64)handle) << 32, HW_PAGE_SIZE, 0, 0);
 137
 138        if (hvrc != HvLpEvent_Rc_Good)
 139                printk(VIOPATH_KERN_WARN "hv error on op %d\n", (int)hvrc);
 140
 141        wait_for_completion(&done);
 142
 143        vlanMap = HvLpConfig_getVirtualLanIndexMap();
 144
 145        buf[HW_PAGE_SIZE-1] = '\0';
 146        seq_printf(m, "%s", buf);
 147
 148        iseries_hv_unmap(handle, HW_PAGE_SIZE, DMA_FROM_DEVICE);
 149        kfree(buf);
 150
 151        seq_printf(m, "AVAILABLE_VETH=%x\n", vlanMap);
 152
 153        node = of_find_node_by_path("/");
 154        sysid = NULL;
 155        if (node != NULL)
 156                sysid = of_get_property(node, "system-id", NULL);
 157
 158        if (sysid == NULL)
 159                seq_printf(m, "SRLNBR=<UNKNOWN>\n");
 160        else
 161                /* Skip "IBM," on front of serial number, see dt.c */
 162                seq_printf(m, "SRLNBR=%s\n", sysid + 4);
 163
 164        of_node_put(node);
 165
 166        return 0;
 167}
 168
 169static int proc_viopath_open(struct inode *inode, struct file *file)
 170{
 171        return single_open(file, proc_viopath_show, NULL);
 172}
 173
 174static const struct file_operations proc_viopath_operations = {
 175        .open           = proc_viopath_open,
 176        .read           = seq_read,
 177        .llseek         = seq_lseek,
 178        .release        = single_release,
 179};
 180
 181static int __init vio_proc_init(void)
 182{
 183        if (!firmware_has_feature(FW_FEATURE_ISERIES))
 184                return 0;
 185
 186        proc_create("iSeries/config", 0, NULL, &proc_viopath_operations);
 187        return 0;
 188}
 189__initcall(vio_proc_init);
 190
 191/* See if a given LP is active.  Allow for invalid lps to be passed in
 192 * and just return invalid
 193 */
 194int viopath_isactive(HvLpIndex lp)
 195{
 196        if (lp == HvLpIndexInvalid)
 197                return 0;
 198        if (lp < HVMAXARCHITECTEDLPS)
 199                return viopathStatus[lp].isActive;
 200        else
 201                return 0;
 202}
 203EXPORT_SYMBOL(viopath_isactive);
 204
 205/*
 206 * We cache the source and target instance ids for each
 207 * partition.
 208 */
 209HvLpInstanceId viopath_sourceinst(HvLpIndex lp)
 210{
 211        return viopathStatus[lp].mSourceInst;
 212}
 213EXPORT_SYMBOL(viopath_sourceinst);
 214
 215HvLpInstanceId viopath_targetinst(HvLpIndex lp)
 216{
 217        return viopathStatus[lp].mTargetInst;
 218}
 219EXPORT_SYMBOL(viopath_targetinst);
 220
 221/*
 222 * Send a monitor message.  This is a message with the acknowledge
 223 * bit on that the other side will NOT explicitly acknowledge.  When
 224 * the other side goes down, the hypervisor will acknowledge any
 225 * outstanding messages....so we will know when the other side dies.
 226 */
 227static void sendMonMsg(HvLpIndex remoteLp)
 228{
 229        HvLpEvent_Rc hvrc;
 230
 231        viopathStatus[remoteLp].mSourceInst =
 232                HvCallEvent_getSourceLpInstanceId(remoteLp,
 233                                HvLpEvent_Type_VirtualIo);
 234        viopathStatus[remoteLp].mTargetInst =
 235                HvCallEvent_getTargetLpInstanceId(remoteLp,
 236                                HvLpEvent_Type_VirtualIo);
 237
 238        /*
 239         * Deliberately ignore the return code here.  if we call this
 240         * more than once, we don't care.
 241         */
 242        vio_setHandler(viomajorsubtype_monitor, handleMonitorEvent);
 243
 244        hvrc = HvCallEvent_signalLpEventFast(remoteLp, HvLpEvent_Type_VirtualIo,
 245                        viomajorsubtype_monitor, HvLpEvent_AckInd_DoAck,
 246                        HvLpEvent_AckType_DeferredAck,
 247                        viopathStatus[remoteLp].mSourceInst,
 248                        viopathStatus[remoteLp].mTargetInst,
 249                        viomonseq++, 0, 0, 0, 0, 0);
 250
 251        if (hvrc == HvLpEvent_Rc_Good)
 252                viopathStatus[remoteLp].isActive = 1;
 253        else {
 254                printk(VIOPATH_KERN_WARN "could not connect to partition %d\n",
 255                                remoteLp);
 256                viopathStatus[remoteLp].isActive = 0;
 257        }
 258}
 259
 260static void handleMonitorEvent(struct HvLpEvent *event)
 261{
 262        HvLpIndex remoteLp;
 263        int i;
 264
 265        /*
 266         * This handler is _also_ called as part of the loop
 267         * at the end of this routine, so it must be able to
 268         * ignore NULL events...
 269         */
 270        if (!event)
 271                return;
 272
 273        /*
 274         * First see if this is just a normal monitor message from the
 275         * other partition
 276         */
 277        if (hvlpevent_is_int(event)) {
 278                remoteLp = event->xSourceLp;
 279                if (!viopathStatus[remoteLp].isActive)
 280                        sendMonMsg(remoteLp);
 281                return;
 282        }
 283
 284        /*
 285         * This path is for an acknowledgement; the other partition
 286         * died
 287         */
 288        remoteLp = event->xTargetLp;
 289        if ((event->xSourceInstanceId != viopathStatus[remoteLp].mSourceInst) ||
 290            (event->xTargetInstanceId != viopathStatus[remoteLp].mTargetInst)) {
 291                printk(VIOPATH_KERN_WARN "ignoring ack....mismatched instances\n");
 292                return;
 293        }
 294
 295        printk(VIOPATH_KERN_WARN "partition %d ended\n", remoteLp);
 296
 297        viopathStatus[remoteLp].isActive = 0;
 298
 299        /*
 300         * For each active handler, pass them a NULL
 301         * message to indicate that the other partition
 302         * died
 303         */
 304        for (i = 0; i < VIO_MAX_SUBTYPES; i++) {
 305                if (vio_handler[i] != NULL)
 306                        (*vio_handler[i])(NULL);
 307        }
 308}
 309
 310int vio_setHandler(int subtype, vio_event_handler_t *beh)
 311{
 312        subtype = subtype >> VIOMAJOR_SUBTYPE_SHIFT;
 313        if ((subtype < 0) || (subtype >= VIO_MAX_SUBTYPES))
 314                return -EINVAL;
 315        if (vio_handler[subtype] != NULL)
 316                return -EBUSY;
 317        vio_handler[subtype] = beh;
 318        return 0;
 319}
 320EXPORT_SYMBOL(vio_setHandler);
 321
 322int vio_clearHandler(int subtype)
 323{
 324        subtype = subtype >> VIOMAJOR_SUBTYPE_SHIFT;
 325        if ((subtype < 0) || (subtype >= VIO_MAX_SUBTYPES))
 326                return -EINVAL;
 327        if (vio_handler[subtype] == NULL)
 328                return -EAGAIN;
 329        vio_handler[subtype] = NULL;
 330        return 0;
 331}
 332EXPORT_SYMBOL(vio_clearHandler);
 333
 334static void handleConfig(struct HvLpEvent *event)
 335{
 336        if (!event)
 337                return;
 338        if (hvlpevent_is_int(event)) {
 339                printk(VIOPATH_KERN_WARN
 340                       "unexpected config request from partition %d",
 341                       event->xSourceLp);
 342
 343                if (hvlpevent_need_ack(event)) {
 344                        event->xRc = HvLpEvent_Rc_InvalidSubtype;
 345                        HvCallEvent_ackLpEvent(event);
 346                }
 347                return;
 348        }
 349
 350        complete((struct completion *)event->xCorrelationToken);
 351}
 352
 353/*
 354 * Initialization of the hosting partition
 355 */
 356void vio_set_hostlp(void)
 357{
 358        /*
 359         * If this has already been set then we DON'T want to either change
 360         * it or re-register the proc file system
 361         */
 362        if (viopath_hostLp != HvLpIndexInvalid)
 363                return;
 364
 365        /*
 366         * Figure out our hosting partition.  This isn't allowed to change
 367         * while we're active
 368         */
 369        viopath_ourLp = HvLpConfig_getLpIndex();
 370        viopath_hostLp = HvLpConfig_getHostingLpIndex(viopath_ourLp);
 371
 372        if (viopath_hostLp != HvLpIndexInvalid)
 373                vio_setHandler(viomajorsubtype_config, handleConfig);
 374}
 375EXPORT_SYMBOL(vio_set_hostlp);
 376
 377static void vio_handleEvent(struct HvLpEvent *event)
 378{
 379        HvLpIndex remoteLp;
 380        int subtype = (event->xSubtype & VIOMAJOR_SUBTYPE_MASK)
 381                >> VIOMAJOR_SUBTYPE_SHIFT;
 382
 383        if (hvlpevent_is_int(event)) {
 384                remoteLp = event->xSourceLp;
 385                /*
 386                 * The isActive is checked because if the hosting partition
 387                 * went down and came back up it would not be active but it
 388                 * would have different source and target instances, in which
 389                 * case we'd want to reset them.  This case really protects
 390                 * against an unauthorized active partition sending interrupts
 391                 * or acks to this linux partition.
 392                 */
 393                if (viopathStatus[remoteLp].isActive
 394                    && (event->xSourceInstanceId !=
 395                        viopathStatus[remoteLp].mTargetInst)) {
 396                        printk(VIOPATH_KERN_WARN
 397                               "message from invalid partition. "
 398                               "int msg rcvd, source inst (%d) doesnt match (%d)\n",
 399                               viopathStatus[remoteLp].mTargetInst,
 400                               event->xSourceInstanceId);
 401                        return;
 402                }
 403
 404                if (viopathStatus[remoteLp].isActive
 405                    && (event->xTargetInstanceId !=
 406                        viopathStatus[remoteLp].mSourceInst)) {
 407                        printk(VIOPATH_KERN_WARN
 408                               "message from invalid partition. "
 409                               "int msg rcvd, target inst (%d) doesnt match (%d)\n",
 410                               viopathStatus[remoteLp].mSourceInst,
 411                               event->xTargetInstanceId);
 412                        return;
 413                }
 414        } else {
 415                remoteLp = event->xTargetLp;
 416                if (event->xSourceInstanceId !=
 417                    viopathStatus[remoteLp].mSourceInst) {
 418                        printk(VIOPATH_KERN_WARN
 419                               "message from invalid partition. "
 420                               "ack msg rcvd, source inst (%d) doesnt match (%d)\n",
 421                               viopathStatus[remoteLp].mSourceInst,
 422                               event->xSourceInstanceId);
 423                        return;
 424                }
 425
 426                if (event->xTargetInstanceId !=
 427                    viopathStatus[remoteLp].mTargetInst) {
 428                        printk(VIOPATH_KERN_WARN
 429                               "message from invalid partition. "
 430                               "viopath: ack msg rcvd, target inst (%d) doesnt match (%d)\n",
 431                               viopathStatus[remoteLp].mTargetInst,
 432                               event->xTargetInstanceId);
 433                        return;
 434                }
 435        }
 436
 437        if (vio_handler[subtype] == NULL) {
 438                printk(VIOPATH_KERN_WARN
 439                       "unexpected virtual io event subtype %d from partition %d\n",
 440                       event->xSubtype, remoteLp);
 441                /* No handler.  Ack if necessary */
 442                if (hvlpevent_is_int(event) && hvlpevent_need_ack(event)) {
 443                        event->xRc = HvLpEvent_Rc_InvalidSubtype;
 444                        HvCallEvent_ackLpEvent(event);
 445                }
 446                return;
 447        }
 448
 449        /* This innocuous little line is where all the real work happens */
 450        (*vio_handler[subtype])(event);
 451}
 452
 453static void viopath_donealloc(void *parm, int number)
 454{
 455        struct alloc_parms *parmsp = parm;
 456
 457        parmsp->number = number;
 458        if (parmsp->used_wait_atomic)
 459                atomic_set(&parmsp->wait_atomic, 0);
 460        else
 461                complete(&parmsp->done);
 462}
 463
 464static int allocateEvents(HvLpIndex remoteLp, int numEvents)
 465{
 466        struct alloc_parms parms;
 467
 468        if (system_state != SYSTEM_RUNNING) {
 469                parms.used_wait_atomic = 1;
 470                atomic_set(&parms.wait_atomic, 1);
 471        } else {
 472                parms.used_wait_atomic = 0;
 473                init_completion(&parms.done);
 474        }
 475        mf_allocate_lp_events(remoteLp, HvLpEvent_Type_VirtualIo, 250,  /* It would be nice to put a real number here! */
 476                            numEvents, &viopath_donealloc, &parms);
 477        if (system_state != SYSTEM_RUNNING) {
 478                while (atomic_read(&parms.wait_atomic))
 479                        mb();
 480        } else
 481                wait_for_completion(&parms.done);
 482        return parms.number;
 483}
 484
 485int viopath_open(HvLpIndex remoteLp, int subtype, int numReq)
 486{
 487        int i;
 488        unsigned long flags;
 489        int tempNumAllocated;
 490
 491        if ((remoteLp >= HVMAXARCHITECTEDLPS) || (remoteLp == HvLpIndexInvalid))
 492                return -EINVAL;
 493
 494        subtype = subtype >> VIOMAJOR_SUBTYPE_SHIFT;
 495        if ((subtype < 0) || (subtype >= VIO_MAX_SUBTYPES))
 496                return -EINVAL;
 497
 498        spin_lock_irqsave(&statuslock, flags);
 499
 500        if (!event_buffer_initialised) {
 501                for (i = 0; i < VIO_MAX_SUBTYPES; i++)
 502                        atomic_set(&event_buffer_available[i], 1);
 503                event_buffer_initialised = 1;
 504        }
 505
 506        viopathStatus[remoteLp].users[subtype]++;
 507
 508        if (!viopathStatus[remoteLp].isOpen) {
 509                viopathStatus[remoteLp].isOpen = 1;
 510                HvCallEvent_openLpEventPath(remoteLp, HvLpEvent_Type_VirtualIo);
 511
 512                /*
 513                 * Don't hold the spinlock during an operation that
 514                 * can sleep.
 515                 */
 516                spin_unlock_irqrestore(&statuslock, flags);
 517                tempNumAllocated = allocateEvents(remoteLp, 1);
 518                spin_lock_irqsave(&statuslock, flags);
 519
 520                viopathStatus[remoteLp].numberAllocated += tempNumAllocated;
 521
 522                if (viopathStatus[remoteLp].numberAllocated == 0) {
 523                        HvCallEvent_closeLpEventPath(remoteLp,
 524                                        HvLpEvent_Type_VirtualIo);
 525
 526                        spin_unlock_irqrestore(&statuslock, flags);
 527                        return -ENOMEM;
 528                }
 529
 530                viopathStatus[remoteLp].mSourceInst =
 531                        HvCallEvent_getSourceLpInstanceId(remoteLp,
 532                                        HvLpEvent_Type_VirtualIo);
 533                viopathStatus[remoteLp].mTargetInst =
 534                        HvCallEvent_getTargetLpInstanceId(remoteLp,
 535                                        HvLpEvent_Type_VirtualIo);
 536                HvLpEvent_registerHandler(HvLpEvent_Type_VirtualIo,
 537                                          &vio_handleEvent);
 538                sendMonMsg(remoteLp);
 539                printk(VIOPATH_KERN_INFO "opening connection to partition %d, "
 540                                "setting sinst %d, tinst %d\n",
 541                                remoteLp, viopathStatus[remoteLp].mSourceInst,
 542                                viopathStatus[remoteLp].mTargetInst);
 543        }
 544
 545        spin_unlock_irqrestore(&statuslock, flags);
 546        tempNumAllocated = allocateEvents(remoteLp, numReq);
 547        spin_lock_irqsave(&statuslock, flags);
 548        viopathStatus[remoteLp].numberAllocated += tempNumAllocated;
 549        spin_unlock_irqrestore(&statuslock, flags);
 550
 551        return 0;
 552}
 553EXPORT_SYMBOL(viopath_open);
 554
 555int viopath_close(HvLpIndex remoteLp, int subtype, int numReq)
 556{
 557        unsigned long flags;
 558        int i;
 559        int numOpen;
 560        struct alloc_parms parms;
 561
 562        if ((remoteLp >= HVMAXARCHITECTEDLPS) || (remoteLp == HvLpIndexInvalid))
 563                return -EINVAL;
 564
 565        subtype = subtype >> VIOMAJOR_SUBTYPE_SHIFT;
 566        if ((subtype < 0) || (subtype >= VIO_MAX_SUBTYPES))
 567                return -EINVAL;
 568
 569        spin_lock_irqsave(&statuslock, flags);
 570        /*
 571         * If the viopath_close somehow gets called before a
 572         * viopath_open it could decrement to -1 which is a non
 573         * recoverable state so we'll prevent this from
 574         * happening.
 575         */
 576        if (viopathStatus[remoteLp].users[subtype] > 0)
 577                viopathStatus[remoteLp].users[subtype]--;
 578
 579        spin_unlock_irqrestore(&statuslock, flags);
 580
 581        parms.used_wait_atomic = 0;
 582        init_completion(&parms.done);
 583        mf_deallocate_lp_events(remoteLp, HvLpEvent_Type_VirtualIo,
 584                              numReq, &viopath_donealloc, &parms);
 585        wait_for_completion(&parms.done);
 586
 587        spin_lock_irqsave(&statuslock, flags);
 588        for (i = 0, numOpen = 0; i < VIO_MAX_SUBTYPES; i++)
 589                numOpen += viopathStatus[remoteLp].users[i];
 590
 591        if ((viopathStatus[remoteLp].isOpen) && (numOpen == 0)) {
 592                printk(VIOPATH_KERN_INFO "closing connection to partition %d\n",
 593                                remoteLp);
 594
 595                HvCallEvent_closeLpEventPath(remoteLp,
 596                                             HvLpEvent_Type_VirtualIo);
 597                viopathStatus[remoteLp].isOpen = 0;
 598                viopathStatus[remoteLp].isActive = 0;
 599
 600                for (i = 0; i < VIO_MAX_SUBTYPES; i++)
 601                        atomic_set(&event_buffer_available[i], 0);
 602                event_buffer_initialised = 0;
 603        }
 604        spin_unlock_irqrestore(&statuslock, flags);
 605        return 0;
 606}
 607EXPORT_SYMBOL(viopath_close);
 608
 609void *vio_get_event_buffer(int subtype)
 610{
 611        subtype = subtype >> VIOMAJOR_SUBTYPE_SHIFT;
 612        if ((subtype < 0) || (subtype >= VIO_MAX_SUBTYPES))
 613                return NULL;
 614
 615        if (atomic_dec_if_positive(&event_buffer_available[subtype]) == 0)
 616                return &event_buffer[subtype * 256];
 617        else
 618                return NULL;
 619}
 620EXPORT_SYMBOL(vio_get_event_buffer);
 621
 622void vio_free_event_buffer(int subtype, void *buffer)
 623{
 624        subtype = subtype >> VIOMAJOR_SUBTYPE_SHIFT;
 625        if ((subtype < 0) || (subtype >= VIO_MAX_SUBTYPES)) {
 626                printk(VIOPATH_KERN_WARN
 627                       "unexpected subtype %d freeing event buffer\n", subtype);
 628                return;
 629        }
 630
 631        if (atomic_read(&event_buffer_available[subtype]) != 0) {
 632                printk(VIOPATH_KERN_WARN
 633                       "freeing unallocated event buffer, subtype %d\n",
 634                       subtype);
 635                return;
 636        }
 637
 638        if (buffer != &event_buffer[subtype * 256]) {
 639                printk(VIOPATH_KERN_WARN
 640                       "freeing invalid event buffer, subtype %d\n", subtype);
 641        }
 642
 643        atomic_set(&event_buffer_available[subtype], 1);
 644}
 645EXPORT_SYMBOL(vio_free_event_buffer);
 646
 647static const struct vio_error_entry vio_no_error =
 648    { 0, 0, "Non-VIO Error" };
 649static const struct vio_error_entry vio_unknown_error =
 650    { 0, EIO, "Unknown Error" };
 651
 652static const struct vio_error_entry vio_default_errors[] = {
 653        {0x0001, EIO, "No Connection"},
 654        {0x0002, EIO, "No Receiver"},
 655        {0x0003, EIO, "No Buffer Available"},
 656        {0x0004, EBADRQC, "Invalid Message Type"},
 657        {0x0000, 0, NULL},
 658};
 659
 660const struct vio_error_entry *vio_lookup_rc(
 661                const struct vio_error_entry *local_table, u16 rc)
 662{
 663        const struct vio_error_entry *cur;
 664
 665        if (!rc)
 666                return &vio_no_error;
 667        if (local_table)
 668                for (cur = local_table; cur->rc; ++cur)
 669                        if (cur->rc == rc)
 670                                return cur;
 671        for (cur = vio_default_errors; cur->rc; ++cur)
 672                if (cur->rc == rc)
 673                        return cur;
 674        return &vio_unknown_error;
 675}
 676EXPORT_SYMBOL(vio_lookup_rc);
 677
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.