summaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/char/Kconfig6
-rw-r--r--drivers/char/Makefile1
-rw-r--r--drivers/char/hvc_udbg.c96
-rw-r--r--drivers/of/base.c35
-rw-r--r--drivers/pci/hotplug/rpadlpar_core.c69
-rw-r--r--drivers/ps3/ps3av.c20
-rw-r--r--drivers/ps3/ps3av_cmd.c4
-rw-r--r--drivers/serial/pmac_zilog.c27
-rw-r--r--drivers/video/ps3fb.c17
9 files changed, 202 insertions, 73 deletions
diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig
index 43d6ba83a191..f57907a2c7a1 100644
--- a/drivers/char/Kconfig
+++ b/drivers/char/Kconfig
@@ -631,6 +631,12 @@ config HVC_XEN
help
Xen virtual console device driver
+config HVC_UDBG
+ bool "udbg based fake hypervisor console"
+ depends on PPC && EXPERIMENTAL
+ select HVC_DRIVER
+ default n
+
config VIRTIO_CONSOLE
tristate "Virtio console"
depends on VIRTIO
diff --git a/drivers/char/Makefile b/drivers/char/Makefile
index 438f71317c5c..52e15524af39 100644
--- a/drivers/char/Makefile
+++ b/drivers/char/Makefile
@@ -50,6 +50,7 @@ obj-$(CONFIG_HVC_BEAT) += hvc_beat.o
obj-$(CONFIG_HVC_DRIVER) += hvc_console.o
obj-$(CONFIG_HVC_IRQ) += hvc_irq.o
obj-$(CONFIG_HVC_XEN) += hvc_xen.o
+obj-$(CONFIG_HVC_UDBG) += hvc_udbg.o
obj-$(CONFIG_VIRTIO_CONSOLE) += virtio_console.o
obj-$(CONFIG_RAW_DRIVER) += raw.o
obj-$(CONFIG_SGI_SNSC) += snsc.o snsc_event.o
diff --git a/drivers/char/hvc_udbg.c b/drivers/char/hvc_udbg.c
new file mode 100644
index 000000000000..bd63ba878a56
--- /dev/null
+++ b/drivers/char/hvc_udbg.c
@@ -0,0 +1,96 @@
+/*
+ * udbg interface to hvc_console.c
+ *
+ * (C) Copyright David Gibson, IBM Corporation 2008.
+ *
+ * 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/console.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/moduleparam.h>
+#include <linux/types.h>
+#include <linux/irq.h>
+
+#include <asm/udbg.h>
+
+#include "hvc_console.h"
+
+struct hvc_struct *hvc_udbg_dev;
+
+static int hvc_udbg_put(uint32_t vtermno, const char *buf, int count)
+{
+ int i;
+
+ for (i = 0; i < count; i++)
+ udbg_putc(buf[i]);
+
+ return i;
+}
+
+static int hvc_udbg_get(uint32_t vtermno, char *buf, int count)
+{
+ int i, c;
+
+ if (!udbg_getc_poll)
+ return 0;
+
+ for (i = 0; i < count; i++) {
+ if ((c = udbg_getc_poll()) == -1)
+ break;
+ buf[i] = c;
+ }
+
+ return i;
+}
+
+static struct hv_ops hvc_udbg_ops = {
+ .get_chars = hvc_udbg_get,
+ .put_chars = hvc_udbg_put,
+};
+
+static int __init hvc_udbg_init(void)
+{
+ struct hvc_struct *hp;
+
+ BUG_ON(hvc_udbg_dev);
+
+ hp = hvc_alloc(0, NO_IRQ, &hvc_udbg_ops, 16);
+ if (IS_ERR(hp))
+ return PTR_ERR(hp);
+
+ hvc_udbg_dev = hp;
+
+ return 0;
+}
+module_init(hvc_udbg_init);
+
+static void __exit hvc_udbg_exit(void)
+{
+ if (hvc_udbg_dev)
+ hvc_remove(hvc_udbg_dev);
+}
+module_exit(hvc_udbg_exit);
+
+static int __init hvc_udbg_console_init(void)
+{
+ hvc_instantiate(0, 0, &hvc_udbg_ops);
+ add_preferred_console("hvc", 0, NULL);
+
+ return 0;
+}
+console_initcall(hvc_udbg_console_init);
diff --git a/drivers/of/base.c b/drivers/of/base.c
index 7c79e94a35ea..4f884a358a7b 100644
--- a/drivers/of/base.c
+++ b/drivers/of/base.c
@@ -329,6 +329,41 @@ struct device_node *of_find_compatible_node(struct device_node *from,
EXPORT_SYMBOL(of_find_compatible_node);
/**
+ * of_find_node_with_property - Find a node which has a property with
+ * the given name.
+ * @from: The node to start searching from or NULL, the node
+ * you pass will not be searched, only the next one
+ * will; typically, you pass what the previous call
+ * returned. of_node_put() will be called on it
+ * @prop_name: The name of the property to look for.
+ *
+ * Returns a node pointer with refcount incremented, use
+ * of_node_put() on it when done.
+ */
+struct device_node *of_find_node_with_property(struct device_node *from,
+ const char *prop_name)
+{
+ struct device_node *np;
+ struct property *pp;
+
+ read_lock(&devtree_lock);
+ np = from ? from->allnext : allnodes;
+ for (; np; np = np->allnext) {
+ for (pp = np->properties; pp != 0; pp = pp->next) {
+ if (of_prop_cmp(pp->name, prop_name) == 0) {
+ of_node_get(np);
+ goto out;
+ }
+ }
+ }
+out:
+ of_node_put(from);
+ read_unlock(&devtree_lock);
+ return np;
+}
+EXPORT_SYMBOL(of_find_node_with_property);
+
+/**
* of_match_node - Tell if an device_node has a matching of_match structure
* @matches: array of of device match structures to search in
* @node: the of device structure to match against
diff --git a/drivers/pci/hotplug/rpadlpar_core.c b/drivers/pci/hotplug/rpadlpar_core.c
index 9c2a22fed18b..4e3e0382c16e 100644
--- a/drivers/pci/hotplug/rpadlpar_core.c
+++ b/drivers/pci/hotplug/rpadlpar_core.c
@@ -14,6 +14,9 @@
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*/
+
+#undef DEBUG
+
#include <linux/init.h>
#include <linux/pci.h>
#include <linux/string.h>
@@ -151,20 +154,20 @@ static void dlpar_pci_add_bus(struct device_node *dn)
return;
}
+ /* Scan below the new bridge */
if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE ||
dev->hdr_type == PCI_HEADER_TYPE_CARDBUS)
of_scan_pci_bridge(dn, dev);
- pcibios_fixup_new_pci_devices(dev->subordinate);
-
- /* Claim new bus resources */
- pcibios_claim_one_bus(dev->bus);
-
/* Map IO space for child bus, which may or may not succeed */
pcibios_map_io_space(dev->subordinate);
- /* Add new devices to global lists. Register in proc, sysfs. */
- pci_bus_add_devices(phb->bus);
+ /* Finish adding it : resource allocation, adding devices, etc...
+ * Note that we need to perform the finish pass on the -parent-
+ * bus of the EADS bridge so the bridge device itself gets
+ * properly added
+ */
+ pcibios_finish_adding_to_bus(phb->bus);
}
static int dlpar_add_pci_slot(char *drc_name, struct device_node *dn)
@@ -203,27 +206,6 @@ static int dlpar_add_pci_slot(char *drc_name, struct device_node *dn)
return 0;
}
-static int dlpar_remove_root_bus(struct pci_controller *phb)
-{
- struct pci_bus *phb_bus;
- int rc;
-
- phb_bus = phb->bus;
- if (!(list_empty(&phb_bus->children) &&
- list_empty(&phb_bus->devices))) {
- return -EBUSY;
- }
-
- rc = pcibios_remove_root_bus(phb);
- if (rc)
- return -EIO;
-
- device_unregister(phb_bus->bridge);
- pci_remove_bus(phb_bus);
-
- return 0;
-}
-
static int dlpar_remove_phb(char *drc_name, struct device_node *dn)
{
struct slot *slot;
@@ -235,18 +217,15 @@ static int dlpar_remove_phb(char *drc_name, struct device_node *dn)
/* If pci slot is hotplugable, use hotplug to remove it */
slot = find_php_slot(dn);
- if (slot) {
- if (rpaphp_deregister_slot(slot)) {
- printk(KERN_ERR
- "%s: unable to remove hotplug slot %s\n",
- __func__, drc_name);
- return -EIO;
- }
+ if (slot && rpaphp_deregister_slot(slot)) {
+ printk(KERN_ERR "%s: unable to remove hotplug slot %s\n",
+ __func__, drc_name);
+ return -EIO;
}
pdn = dn->data;
BUG_ON(!pdn || !pdn->phb);
- rc = dlpar_remove_root_bus(pdn->phb);
+ rc = remove_phb_dynamic(pdn->phb);
if (rc < 0)
return rc;
@@ -378,26 +357,38 @@ int dlpar_remove_pci_slot(char *drc_name, struct device_node *dn)
if (!bus)
return -EINVAL;
- /* If pci slot is hotplugable, use hotplug to remove it */
+ pr_debug("PCI: Removing PCI slot below EADS bridge %s\n",
+ bus->self ? pci_name(bus->self) : "<!PHB!>");
+
slot = find_php_slot(dn);
if (slot) {
+ pr_debug("PCI: Removing hotplug slot for %04x:%02x...\n",
+ pci_domain_nr(bus), bus->number);
+
if (rpaphp_deregister_slot(slot)) {
printk(KERN_ERR
"%s: unable to remove hotplug slot %s\n",
__func__, drc_name);
return -EIO;
}
- } else
- pcibios_remove_pci_devices(bus);
+ }
+
+ /* Remove all devices below slot */
+ pcibios_remove_pci_devices(bus);
+ /* Unmap PCI IO space */
if (pcibios_unmap_io_space(bus)) {
printk(KERN_ERR "%s: failed to unmap bus range\n",
__func__);
return -ERANGE;
}
+ /* Remove the EADS bridge device itself */
BUG_ON(!bus->self);
+ pr_debug("PCI: Now removing bridge device %s\n", pci_name(bus->self));
+ eeh_remove_bus_device(bus->self);
pci_remove_bus_device(bus->self);
+
return 0;
}
diff --git a/drivers/ps3/ps3av.c b/drivers/ps3/ps3av.c
index 06848b254d57..5324978b73fb 100644
--- a/drivers/ps3/ps3av.c
+++ b/drivers/ps3/ps3av.c
@@ -59,8 +59,6 @@ static struct ps3av {
struct ps3av_reply_hdr reply_hdr;
u8 raw[PS3AV_BUF_SIZE];
} recv_buf;
- void (*flip_ctl)(int on, void *data);
- void *flip_data;
} *ps3av;
/* color space */
@@ -939,24 +937,6 @@ int ps3av_audio_mute(int mute)
EXPORT_SYMBOL_GPL(ps3av_audio_mute);
-void ps3av_register_flip_ctl(void (*flip_ctl)(int on, void *data),
- void *flip_data)
-{
- mutex_lock(&ps3av->mutex);
- ps3av->flip_ctl = flip_ctl;
- ps3av->flip_data = flip_data;
- mutex_unlock(&ps3av->mutex);
-}
-EXPORT_SYMBOL_GPL(ps3av_register_flip_ctl);
-
-void ps3av_flip_ctl(int on)
-{
- mutex_lock(&ps3av->mutex);
- if (ps3av->flip_ctl)
- ps3av->flip_ctl(on, ps3av->flip_data);
- mutex_unlock(&ps3av->mutex);
-}
-
static int ps3av_probe(struct ps3_system_bus_device *dev)
{
int res;
diff --git a/drivers/ps3/ps3av_cmd.c b/drivers/ps3/ps3av_cmd.c
index 11eb50318fec..716596e8e5b0 100644
--- a/drivers/ps3/ps3av_cmd.c
+++ b/drivers/ps3/ps3av_cmd.c
@@ -864,7 +864,7 @@ int ps3av_cmd_avb_param(struct ps3av_pkt_avb_param *avb, u32 send_len)
{
int res;
- ps3av_flip_ctl(0); /* flip off */
+ mutex_lock(&ps3_gpu_mutex);
/* avb packet */
res = ps3av_do_pkt(PS3AV_CID_AVB_PARAM, send_len, sizeof(*avb),
@@ -878,7 +878,7 @@ int ps3av_cmd_avb_param(struct ps3av_pkt_avb_param *avb, u32 send_len)
res);
out:
- ps3av_flip_ctl(1); /* flip on */
+ mutex_unlock(&ps3_gpu_mutex);
return res;
}
diff --git a/drivers/serial/pmac_zilog.c b/drivers/serial/pmac_zilog.c
index 317b061f7641..ad3488504010 100644
--- a/drivers/serial/pmac_zilog.c
+++ b/drivers/serial/pmac_zilog.c
@@ -1383,6 +1383,29 @@ static int pmz_verify_port(struct uart_port *port, struct serial_struct *ser)
return -EINVAL;
}
+#ifdef CONFIG_CONSOLE_POLL
+
+static int pmz_poll_get_char(struct uart_port *port)
+{
+ struct uart_pmac_port *uap = (struct uart_pmac_port *)port;
+
+ while ((read_zsreg(uap, R0) & Rx_CH_AV) == 0)
+ udelay(5);
+ return read_zsdata(uap);
+}
+
+static void pmz_poll_put_char(struct uart_port *port, unsigned char c)
+{
+ struct uart_pmac_port *uap = (struct uart_pmac_port *)port;
+
+ /* Wait for the transmit buffer to empty. */
+ while ((read_zsreg(uap, R0) & Tx_BUF_EMP) == 0)
+ udelay(5);
+ write_zsdata(uap, c);
+}
+
+#endif
+
static struct uart_ops pmz_pops = {
.tx_empty = pmz_tx_empty,
.set_mctrl = pmz_set_mctrl,
@@ -1400,6 +1423,10 @@ static struct uart_ops pmz_pops = {
.request_port = pmz_request_port,
.config_port = pmz_config_port,
.verify_port = pmz_verify_port,
+#ifdef CONFIG_CONSOLE_POLL
+ .poll_get_char = pmz_poll_get_char,
+ .poll_put_char = pmz_poll_put_char,
+#endif
};
/*
diff --git a/drivers/video/ps3fb.c b/drivers/video/ps3fb.c
index 4b5d80771904..bd3e39baf7d2 100644
--- a/drivers/video/ps3fb.c
+++ b/drivers/video/ps3fb.c
@@ -460,12 +460,16 @@ static void ps3fb_sync_image(struct device *dev, u64 frame_offset,
line_length |= (u64)src_line_length << 32;
src_offset += GPU_FB_START;
+
+ mutex_lock(&ps3_gpu_mutex);
status = lv1_gpu_context_attribute(ps3fb.context_handle,
L1GPU_CONTEXT_ATTRIBUTE_FB_BLIT,
dst_offset, GPU_IOIF + src_offset,
L1GPU_FB_BLIT_WAIT_FOR_COMPLETION |
(width << 16) | height,
line_length);
+ mutex_unlock(&ps3_gpu_mutex);
+
if (status)
dev_err(dev,
"%s: lv1_gpu_context_attribute FB_BLIT failed: %d\n",
@@ -784,15 +788,6 @@ static int ps3fb_wait_for_vsync(u32 crtc)
return 0;
}
-static void ps3fb_flip_ctl(int on, void *data)
-{
- struct ps3fb_priv *priv = data;
- if (on)
- atomic_dec_if_positive(&priv->ext_flip);
- else
- atomic_inc(&priv->ext_flip);
-}
-
/*
* ioctl
@@ -1228,7 +1223,6 @@ static int __devinit ps3fb_probe(struct ps3_system_bus_device *dev)
}
ps3fb.task = task;
- ps3av_register_flip_ctl(ps3fb_flip_ctl, &ps3fb);
return 0;
@@ -1258,10 +1252,9 @@ static int ps3fb_shutdown(struct ps3_system_bus_device *dev)
dev_dbg(&dev->core, " -> %s:%d\n", __func__, __LINE__);
- ps3fb_flip_ctl(0, &ps3fb); /* flip off */
+ atomic_inc(&ps3fb.ext_flip); /* flip off */
ps3fb.dinfo->irq.mask = 0;
- ps3av_register_flip_ctl(NULL, NULL);
if (ps3fb.task) {
struct task_struct *task = ps3fb.task;
ps3fb.task = NULL;
OpenPOWER on IntegriCloud