diff options
| -rw-r--r-- | drivers/misc/Kconfig | 13 | ||||
| -rw-r--r-- | drivers/misc/Makefile | 1 | ||||
| -rw-r--r-- | drivers/misc/hpilo.c | 768 | ||||
| -rw-r--r-- | drivers/misc/hpilo.h | 189 |
4 files changed, 971 insertions, 0 deletions
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index 1921b8dbb242..ce67d973d349 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig | |||
| @@ -420,4 +420,17 @@ config SGI_XP | |||
| 420 | this feature will allow for direct communication between SSIs | 420 | this feature will allow for direct communication between SSIs |
| 421 | based on a network adapter and DMA messaging. | 421 | based on a network adapter and DMA messaging. |
| 422 | 422 | ||
| 423 | config HP_ILO | ||
| 424 | tristate "Channel interface driver for HP iLO/iLO2 processor" | ||
| 425 | default n | ||
| 426 | help | ||
| 427 | The channel interface driver allows applications to communicate | ||
| 428 | with iLO/iLO2 management processors present on HP ProLiant | ||
| 429 | servers. Upon loading, the driver creates /dev/hpilo/dXccbN files, | ||
| 430 | which can be used to gather data from the management processor, | ||
| 431 | via read and write system calls. | ||
| 432 | |||
| 433 | To compile this driver as a module, choose M here: the | ||
| 434 | module will be called hpilo. | ||
| 435 | |||
| 423 | endif # MISC_DEVICES | 436 | endif # MISC_DEVICES |
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index a6dac6a2e7e5..688fe76135e0 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile | |||
| @@ -27,3 +27,4 @@ obj-$(CONFIG_INTEL_MENLOW) += intel_menlow.o | |||
| 27 | obj-$(CONFIG_ENCLOSURE_SERVICES) += enclosure.o | 27 | obj-$(CONFIG_ENCLOSURE_SERVICES) += enclosure.o |
| 28 | obj-$(CONFIG_KGDB_TESTS) += kgdbts.o | 28 | obj-$(CONFIG_KGDB_TESTS) += kgdbts.o |
| 29 | obj-$(CONFIG_SGI_XP) += sgi-xp/ | 29 | obj-$(CONFIG_SGI_XP) += sgi-xp/ |
| 30 | obj-$(CONFIG_HP_ILO) += hpilo.o | ||
diff --git a/drivers/misc/hpilo.c b/drivers/misc/hpilo.c new file mode 100644 index 000000000000..05e298289238 --- /dev/null +++ b/drivers/misc/hpilo.c | |||
| @@ -0,0 +1,768 @@ | |||
| 1 | /* | ||
| 2 | * Driver for HP iLO/iLO2 management processor. | ||
| 3 | * | ||
| 4 | * Copyright (C) 2008 Hewlett-Packard Development Company, L.P. | ||
| 5 | * David Altobelli <david.altobelli@hp.com> | ||
| 6 | * | ||
| 7 | * This program is free software; you can redistribute it and/or modify | ||
| 8 | * it under the terms of the GNU General Public License version 2 as | ||
| 9 | * published by the Free Software Foundation. | ||
| 10 | */ | ||
| 11 | #include <linux/kernel.h> | ||
| 12 | #include <linux/types.h> | ||
| 13 | #include <linux/module.h> | ||
| 14 | #include <linux/fs.h> | ||
| 15 | #include <linux/pci.h> | ||
| 16 | #include <linux/ioport.h> | ||
| 17 | #include <linux/device.h> | ||
| 18 | #include <linux/file.h> | ||
| 19 | #include <linux/cdev.h> | ||
| 20 | #include <linux/spinlock.h> | ||
| 21 | #include <linux/delay.h> | ||
| 22 | #include <linux/uaccess.h> | ||
| 23 | #include <linux/io.h> | ||
| 24 | #include "hpilo.h" | ||
| 25 | |||
| 26 | static struct class *ilo_class; | ||
| 27 | static unsigned int ilo_major; | ||
| 28 | static char ilo_hwdev[MAX_ILO_DEV]; | ||
| 29 | |||
| 30 | static inline int get_entry_id(int entry) | ||
| 31 | { | ||
| 32 | return (entry & ENTRY_MASK_DESCRIPTOR) >> ENTRY_BITPOS_DESCRIPTOR; | ||
| 33 | } | ||
| 34 | |||
| 35 | static inline int get_entry_len(int entry) | ||
| 36 | { | ||
| 37 | return ((entry & ENTRY_MASK_QWORDS) >> ENTRY_BITPOS_QWORDS) << 3; | ||
| 38 | } | ||
| 39 | |||
| 40 | static inline int mk_entry(int id, int len) | ||
| 41 | { | ||
| 42 | int qlen = len & 7 ? (len >> 3) + 1 : len >> 3; | ||
| 43 | return id << ENTRY_BITPOS_DESCRIPTOR | qlen << ENTRY_BITPOS_QWORDS; | ||
| 44 | } | ||
| 45 | |||
| 46 | static inline int desc_mem_sz(int nr_entry) | ||
| 47 | { | ||
| 48 | return nr_entry << L2_QENTRY_SZ; | ||
| 49 | } | ||
| 50 | |||
| 51 | /* | ||
| 52 | * FIFO queues, shared with hardware. | ||
| 53 | * | ||
| 54 | * If a queue has empty slots, an entry is added to the queue tail, | ||
| 55 | * and that entry is marked as occupied. | ||
| 56 | * Entries can be dequeued from the head of the list, when the device | ||
| 57 | * has marked the entry as consumed. | ||
| 58 | * | ||
| 59 | * Returns true on successful queue/dequeue, false on failure. | ||
| 60 | */ | ||
| 61 | static int fifo_enqueue(struct ilo_hwinfo *hw, char *fifobar, int entry) | ||
| 62 | { | ||
| 63 | struct fifo *fifo_q = FIFOBARTOHANDLE(fifobar); | ||
| 64 | int ret = 0; | ||
| 65 | |||
| 66 | spin_lock(&hw->fifo_lock); | ||
| 67 | if (!(fifo_q->fifobar[(fifo_q->tail + 1) & fifo_q->imask] | ||
| 68 | & ENTRY_MASK_O)) { | ||
| 69 | fifo_q->fifobar[fifo_q->tail & fifo_q->imask] |= | ||
| 70 | (entry & ENTRY_MASK_NOSTATE) | fifo_q->merge; | ||
| 71 | fifo_q->tail += 1; | ||
| 72 | ret = 1; | ||
| 73 | } | ||
| 74 | spin_unlock(&hw->fifo_lock); | ||
| 75 | |||
| 76 | return ret; | ||
| 77 | } | ||
| 78 | |||
| 79 | static int fifo_dequeue(struct ilo_hwinfo *hw, char *fifobar, int *entry) | ||
| 80 | { | ||
| 81 | struct fifo *fifo_q = FIFOBARTOHANDLE(fifobar); | ||
| 82 | int ret = 0; | ||
| 83 | u64 c; | ||
| 84 | |||
| 85 | spin_lock(&hw->fifo_lock); | ||
| 86 | c = fifo_q->fifobar[fifo_q->head & fifo_q->imask]; | ||
| 87 | if (c & ENTRY_MASK_C) { | ||
| 88 | if (entry) | ||
| 89 | *entry = c & ENTRY_MASK_NOSTATE; | ||
| 90 | |||
| 91 | fifo_q->fifobar[fifo_q->head & fifo_q->imask] = | ||
| 92 | (c | ENTRY_MASK) + 1; | ||
| 93 | fifo_q->head += 1; | ||
| 94 | ret = 1; | ||
| 95 | } | ||
| 96 | spin_unlock(&hw->fifo_lock); | ||
| 97 | |||
| 98 | return ret; | ||
| 99 | } | ||
| 100 | |||
| 101 | static int ilo_pkt_enqueue(struct ilo_hwinfo *hw, struct ccb *ccb, | ||
| 102 | int dir, int id, int len) | ||
| 103 | { | ||
| 104 | char *fifobar; | ||
| 105 | int entry; | ||
| 106 | |||
| 107 | if (dir == SENDQ) | ||
| 108 | fifobar = ccb->ccb_u1.send_fifobar; | ||
| 109 | else | ||
| 110 | fifobar = ccb->ccb_u3.recv_fifobar; | ||
| 111 | |||
| 112 | entry = mk_entry(id, len); | ||
| 113 | return fifo_enqueue(hw, fifobar, entry); | ||
| 114 | } | ||
| 115 | |||
| 116 | static int ilo_pkt_dequeue(struct ilo_hwinfo *hw, struct ccb *ccb, | ||
| 117 | int dir, int *id, int *len, void **pkt) | ||
| 118 | { | ||
| 119 | char *fifobar, *desc; | ||
| 120 | int entry = 0, pkt_id = 0; | ||
| 121 | int ret; | ||
| 122 | |||
| 123 | if (dir == SENDQ) { | ||
| 124 | fifobar = ccb->ccb_u1.send_fifobar; | ||
| 125 | desc = ccb->ccb_u2.send_desc; | ||
| 126 | } else { | ||
| 127 | fifobar = ccb->ccb_u3.recv_fifobar; | ||
| 128 | desc = ccb->ccb_u4.recv_desc; | ||
| 129 | } | ||
| 130 | |||
| 131 | ret = fifo_dequeue(hw, fifobar, &entry); | ||
| 132 | if (ret) { | ||
| 133 | pkt_id = get_entry_id(entry); | ||
| 134 | if (id) | ||
| 135 | *id = pkt_id; | ||
| 136 | if (len) | ||
| 137 | *len = get_entry_len(entry); | ||
| 138 | if (pkt) | ||
| 139 | *pkt = (void *)(desc + desc_mem_sz(pkt_id)); | ||
| 140 | } | ||
| 141 | |||
| 142 | return ret; | ||
| 143 | } | ||
| 144 | |||
| 145 | static inline void doorbell_set(struct ccb *ccb) | ||
| 146 | { | ||
| 147 | iowrite8(1, ccb->ccb_u5.db_base); | ||
| 148 | } | ||
| 149 | |||
| 150 | static inline void doorbell_clr(struct ccb *ccb) | ||
| 151 | { | ||
| 152 | iowrite8(2, ccb->ccb_u5.db_base); | ||
| 153 | } | ||
| 154 | static inline int ctrl_set(int l2sz, int idxmask, int desclim) | ||
| 155 | { | ||
| 156 | int active = 0, go = 1; | ||
| 157 | return l2sz << CTRL_BITPOS_L2SZ | | ||
| 158 | idxmask << CTRL_BITPOS_FIFOINDEXMASK | | ||
| 159 | desclim << CTRL_BITPOS_DESCLIMIT | | ||
| 160 | active << CTRL_BITPOS_A | | ||
| 161 | go << CTRL_BITPOS_G; | ||
| 162 | } | ||
| 163 | static void ctrl_setup(struct ccb *ccb, int nr_desc, int l2desc_sz) | ||
| 164 | { | ||
| 165 | /* for simplicity, use the same parameters for send and recv ctrls */ | ||
| 166 | ccb->send_ctrl = ctrl_set(l2desc_sz, nr_desc-1, nr_desc-1); | ||
| 167 | ccb->recv_ctrl = ctrl_set(l2desc_sz, nr_desc-1, nr_desc-1); | ||
| 168 | } | ||
| 169 | |||
| 170 | static inline int fifo_sz(int nr_entry) | ||
| 171 | { | ||
| 172 | /* size of a fifo is determined by the number of entries it contains */ | ||
| 173 | return (nr_entry * sizeof(u64)) + FIFOHANDLESIZE; | ||
| 174 | } | ||
| 175 | |||
