Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 67547
b: refs/heads/master
c: b833b48
h: refs/heads/master
i:
  67545: d1aa29b
  67543: 6f1a51d
v: v3
  • Loading branch information
Stephen Rothwell authored and Paul Mackerras committed Oct 11, 2007
1 parent c383653 commit c211170
Show file tree
Hide file tree
Showing 7 changed files with 362 additions and 106 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: dd9b67ab37d57da67840276d28957498512d4dd8
refs/heads/master: b833b481c10cf591b15cc674948cc514e55d3b94
3 changes: 0 additions & 3 deletions trunk/arch/powerpc/kernel/vio.c
Original file line number Diff line number Diff line change
Expand Up @@ -247,9 +247,6 @@ static int __init vio_bus_init(void)
int err;
struct device_node *node_vroot;

if (firmware_has_feature(FW_FEATURE_ISERIES))
iommu_vio_init();

err = bus_register(&vio_bus_type);
if (err) {
printk(KERN_ERR "failed to register VIO bus\n");
Expand Down
2 changes: 1 addition & 1 deletion trunk/arch/powerpc/platforms/iseries/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ obj-y += hvlog.o hvlpconfig.o lpardata.o setup.o dt_mod.o mf.o lpevents.o \
hvcall.o proc.o htab.o iommu.o misc.o irq.o
obj-$(CONFIG_PCI) += pci.o vpdinfo.o
obj-$(CONFIG_SMP) += smp.o
obj-$(CONFIG_VIOPATH) += viopath.o
obj-$(CONFIG_VIOPATH) += viopath.o vio.o
obj-$(CONFIG_MODULES) += ksyms.o

quiet_cmd_dt_strings = DT_STR $@
Expand Down
4 changes: 0 additions & 4 deletions trunk/arch/powerpc/platforms/iseries/dt.c
Original file line number Diff line number Diff line change
Expand Up @@ -381,10 +381,6 @@ static void __init dt_vdevices(struct iseries_flat_dt *dt)
dt_do_vdevice(dt, "viodasd", reg, i, device_type_block,
"IBM,iSeries-viodasd", 1);
reg += HVMAXARCHITECTEDVIRTUALDISKS;

for (i = 0; i < HVMAXARCHITECTEDVIRTUALCDROMS; i++)
dt_do_vdevice(dt, "viocd", reg, i, device_type_block,
"IBM,iSeries-viocd", 1);
reg += HVMAXARCHITECTEDVIRTUALCDROMS;

for (i = 0; i < HVMAXARCHITECTEDVIRTUALTAPES; i++)
Expand Down
317 changes: 317 additions & 0 deletions trunk/arch/powerpc/platforms/iseries/vio.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,317 @@
/*
* Legacy iSeries specific vio initialisation
* that needs to be built in (not a module).
*
* © Copyright 2007 IBM Corporation
* Author: Stephen Rothwell
* Some parts collected from various other files
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <linux/of.h>
#include <linux/init.h>
#include <linux/gfp.h>
#include <linux/completion.h>
#include <linux/proc_fs.h>

#include <asm/firmware.h>
#include <asm/iseries/vio.h>
#include <asm/iseries/iommu.h>
#include <asm/iseries/hv_types.h>
#include <asm/iseries/hv_lp_event.h>

#define FIRST_VTY 0
#define NUM_VTYS 1
#define FIRST_VSCSI (FIRST_VTY + NUM_VTYS)
#define NUM_VSCSIS 1
#define FIRST_VLAN (FIRST_VSCSI + NUM_VSCSIS)
#define NUM_VLANS HVMAXARCHITECTEDVIRTUALLANS
#define FIRST_VIODASD (FIRST_VLAN + NUM_VLANS)
#define NUM_VIODASDS HVMAXARCHITECTEDVIRTUALDISKS
#define FIRST_VIOCD (FIRST_VIODASD + NUM_VIODASDS)
#define NUM_VIOCDS HVMAXARCHITECTEDVIRTUALCDROMS
#define FIRST_VIOTAPE (FIRST_VIOCD + NUM_VIOCDS)
#define NUM_VIOTAPES HVMAXARCHITECTEDVIRTUALTAPES

static struct property * __init new_property(const char *name, int length,
const void *value)
{
struct property *np = kzalloc(sizeof(*np) + strlen(name) + 1 + length,
GFP_KERNEL);

if (!np)
return NULL;
np->name = (char *)(np + 1);
np->value = np->name + strlen(name) + 1;
strcpy(np->name, name);
memcpy(np->value, value, length);
np->length = length;
return np;
}

static void __init free_property(struct property *np)
{
kfree(np);
}

static struct device_node * __init new_node(const char *path,
struct device_node *parent)
{
struct device_node *np = kzalloc(sizeof(*np), GFP_KERNEL);

if (!np)
return NULL;
np->full_name = kmalloc(strlen(path) + 1, GFP_KERNEL);
if (!np->full_name) {
kfree(np);
return NULL;
}
strcpy(np->full_name, path);
of_node_set_flag(np, OF_DYNAMIC);
kref_init(&np->kref);
np->parent = of_node_get(parent);
return np;
}

static void __init free_node(struct device_node *np)
{
struct property *next;
struct property *prop;

next = np->properties;
while (next) {
prop = next;
next = prop->next;
free_property(prop);
}
of_node_put(np->parent);
kfree(np->full_name);
kfree(np);
}

static int __init add_string_property(struct device_node *np, const char *name,
const char *value)
{
struct property *nprop = new_property(name, strlen(value) + 1, value);

if (!nprop)
return 0;
prom_add_property(np, nprop);
return 1;
}

static int __init add_raw_property(struct device_node *np, const char *name,
int length, const void *value)
{
struct property *nprop = new_property(name, length, value);

if (!nprop)
return 0;
prom_add_property(np, nprop);
return 1;
}

struct viocd_waitevent {
struct completion com;
int rc;
u16 sub_result;
};

struct cdrom_info {
char rsrcname[10];
char type[4];
char model[3];
};

static void __init handle_cd_event(struct HvLpEvent *event)
{
struct viocdlpevent *bevent;
struct viocd_waitevent *pwe;

if (!event)
/* Notification that a partition went away! */
return;

/* First, we should NEVER get an int here...only acks */
if (hvlpevent_is_int(event)) {
printk(KERN_WARNING "handle_cd_event: got an unexpected int\n");
if (hvlpevent_need_ack(event)) {
event->xRc = HvLpEvent_Rc_InvalidSubtype;
HvCallEvent_ackLpEvent(event);
}
return;
}

bevent = (struct viocdlpevent *)event;

switch (event->xSubtype & VIOMINOR_SUBTYPE_MASK) {
case viocdgetinfo:
pwe = (struct viocd_waitevent *)event->xCorrelationToken;
pwe->rc = event->xRc;
pwe->sub_result = bevent->sub_result;
complete(&pwe->com);
break;

default:
printk(KERN_WARNING "handle_cd_event: "
"message with unexpected subtype %0x04X!\n",
event->xSubtype & VIOMINOR_SUBTYPE_MASK);
if (hvlpevent_need_ack(event)) {
event->xRc = HvLpEvent_Rc_InvalidSubtype;
HvCallEvent_ackLpEvent(event);
}
}
}

static void __init get_viocd_info(struct device_node *vio_root)
{
HvLpEvent_Rc hvrc;
u32 unit;
struct viocd_waitevent we;
struct cdrom_info *unitinfo;
dma_addr_t unitinfo_dmaaddr;
int ret;

ret = viopath_open(viopath_hostLp, viomajorsubtype_cdio, 2);
if (ret) {
printk(KERN_WARNING
"get_viocd_info: error opening path to host partition %d\n",
viopath_hostLp);
return;
}

/* Initialize our request handler */
vio_setHandler(viomajorsubtype_cdio, handle_cd_event);

unitinfo = iseries_hv_alloc(
sizeof(*unitinfo) * HVMAXARCHITECTEDVIRTUALCDROMS,
&unitinfo_dmaaddr, GFP_ATOMIC);
if (!unitinfo) {
printk(KERN_WARNING
"get_viocd_info: error allocating unitinfo\n");
goto clear_handler;
}

memset(unitinfo, 0, sizeof(*unitinfo) * HVMAXARCHITECTEDVIRTUALCDROMS);

init_completion(&we.com);

hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp,
HvLpEvent_Type_VirtualIo,
viomajorsubtype_cdio | viocdgetinfo,
HvLpEvent_AckInd_DoAck, HvLpEvent_AckType_ImmediateAck,
viopath_sourceinst(viopath_hostLp),
viopath_targetinst(viopath_hostLp),
(u64)&we, VIOVERSION << 16, unitinfo_dmaaddr, 0,
sizeof(*unitinfo) * HVMAXARCHITECTEDVIRTUALCDROMS, 0);
if (hvrc != HvLpEvent_Rc_Good) {
printk(KERN_WARNING
"get_viocd_info: cdrom error sending event. rc %d\n",
(int)hvrc);
goto hv_free;
}

wait_for_completion(&we.com);

if (we.rc) {
printk(KERN_WARNING "get_viocd_info: bad rc %d:0x%04X\n",
we.rc, we.sub_result);
goto hv_free;
}

for (unit = 0; (unit < HVMAXARCHITECTEDVIRTUALCDROMS) &&
unitinfo[unit].rsrcname[0]; unit++) {
struct device_node *np;
char name[64];
u32 reg = FIRST_VIOCD + unit;

snprintf(name, sizeof(name), "/vdevice/viocd@%08x", reg);
np = new_node(name, vio_root);
if (!np)
goto hv_free;
if (!add_string_property(np, "name", "viocd") ||
!add_string_property(np, "device_type", "block") ||
!add_string_property(np, "compatible",
"IBM,iSeries-viocd") ||
!add_raw_property(np, "reg", sizeof(reg), &reg) ||
!add_raw_property(np, "linux,unit_address",
sizeof(unit), &unit) ||
!add_raw_property(np, "linux,vio_rsrcname",
sizeof(unitinfo[unit].rsrcname),
unitinfo[unit].rsrcname) ||
!add_raw_property(np, "linux,vio_type",
sizeof(unitinfo[unit].type),
unitinfo[unit].type) ||
!add_raw_property(np, "linux,vio_model",
sizeof(unitinfo[unit].model),
unitinfo[unit].model))
goto node_free;
np->name = of_get_property(np, "name", NULL);
np->type = of_get_property(np, "device_type", NULL);
of_attach_node(np);
#ifdef CONFIG_PROC_DEVICETREE
if (vio_root->pde) {
struct proc_dir_entry *ent;

ent = proc_mkdir(strrchr(np->full_name, '/') + 1,
vio_root->pde);
if (ent)
proc_device_tree_add_node(np, ent);
}
#endif
continue;

node_free:
free_node(np);
break;
}

hv_free:
iseries_hv_free(sizeof(*unitinfo) * HVMAXARCHITECTEDVIRTUALCDROMS,
unitinfo, unitinfo_dmaaddr);
clear_handler:
vio_clearHandler(viomajorsubtype_cdio);
viopath_close(viopath_hostLp, viomajorsubtype_cdio, 2);
}

static int __init iseries_vio_init(void)
{
struct device_node *vio_root;

if (!firmware_has_feature(FW_FEATURE_ISERIES))
return -ENODEV;

iommu_vio_init();

vio_root = of_find_node_by_path("/vdevice");
if (!vio_root)
return -ENODEV;

if (viopath_hostLp == HvLpIndexInvalid) {
vio_set_hostlp();
/* If we don't have a host, bail out */
if (viopath_hostLp == HvLpIndexInvalid)
goto put_node;
}

get_viocd_info(vio_root);

return 0;

put_node:
of_node_put(vio_root);
return -ENODEV;
}
arch_initcall(iseries_vio_init);
Loading

0 comments on commit c211170

Please sign in to comment.