* Re: Booting the linux-ppc64 kernel & flattened device tree v0.4
From: Jon Loeliger @ 2005-06-01 19:54 UTC (permalink / raw)
To: Benjamin Herrenschmidt; +Cc: linuxppc-embedded@ozlabs.org
In-Reply-To: <1117614390.19020.24.camel@gaston>
On Wed, 2005-06-01 at 03:26, Benjamin Herrenschmidt wrote:
> DO NOT REPLY TO ALL LISTS PLEASE ! (and CC me on replies).
>
> Here's the fourth version of my document along with new kernel patches
> for the new improved flattened format, and the first release of the
> device-tree "compiler" tool. The patches will be posted as a reply to
> this email. The compiler, dtc, can be downloaded, the URL is in the
> document.
>
> ---
>
> dtc source code can be found at <http://ozlabs.org/~dgibson/dtc/dtc.tar.gz>
Ben,
Here are diffs to:
- Fix multi-line C-style comments.
- Adjust the output of write_tree_source() such that it
separates properties and nodes a bit better.
Thanks,
jdl
diff -u dtc.orig/dtc-lexer.l dtc/dtc-lexer.l
--- dtc.orig/dtc-lexer.l 2005-06-01 11:44:29.000002000 -0500
+++ dtc/dtc-lexer.l 2005-06-01 13:39:56.000001000 -0500
@@ -34,8 +34,6 @@
#include "y.tab.h"
-#undef LEXDEBUG 1
-
%}
\"[^"]*\" {
@@ -102,7 +100,7 @@
<*>{WS}+ /* eat whitespace */
-<*>\/\*[^*]*(\*[^/][^*])*\*\/ /* eat comments */
+<*>\/\*([^*]|\**[^*/])*\*+\/ /* eat C comments */
<*>\/\/.*\n /* eat line comments */
diff -u dtc.orig/treesource.c dtc/treesource.c
--- dtc.orig/treesource.c 2005-06-01 11:44:29.000002000 -0500
+++ dtc/treesource.c 2005-06-01 13:58:33.000001000 -0500
@@ -131,10 +131,16 @@
break;
}
}
- fprintf(f, "\n");
+ if (tree->children) {
+ fprintf(f, "\n");
+ }
for_each_child(tree, child) {
write_tree_source(f, child, level+1);
}
write_prefix(f, level);
fprintf(f, "};\n");
+
+ if (tree->next_sibling) {
+ fprintf(f, "\n");
+ }
}
^ permalink raw reply
* Re: bd_t Cleaning: Board Changes
From: Kumar Gala @ 2005-06-01 18:52 UTC (permalink / raw)
To: Mark A. Greer, Dan Malek, Matt Porter, Tom Rini; +Cc: linuxppc-embedded
In-Reply-To: <429DFA28.30509@mvista.com>
Well, as 85xx/83xx maintainer I'm ok with it. We should probably need
4xx (Matt) and 8xx/82xx (Dan/Tom) agreement.
- kumar
On Jun 1, 2005, at 1:10 PM, Mark A. Greer wrote:
> Jon Loeliger wrote:
>
>> <snip>
>>
>> Part Two of Four, the Board Changes.
>>
>> ppc/platforms/4xx/ash.h | 21 -
>> ppc/platforms/4xx/bubinga.c | 4
>> ppc/platforms/4xx/bubinga.h | 23 -
>> ppc/platforms/4xx/cpci405.h | 2
>> ppc/platforms/4xx/ebony.c | 9
>> ppc/platforms/4xx/ep405.c | 12
>> ppc/platforms/4xx/ep405.h | 13
>> ppc/platforms/4xx/luan.c | 7
>> ppc/platforms/4xx/oak.c | 15
>> ppc/platforms/4xx/oak.h | 19 -
>> ppc/platforms/4xx/oak_setup.h | 2
>> ppc/platforms/4xx/ocotea.c | 13
>> ppc/platforms/4xx/redwood5.h | 13
>> ppc/platforms/4xx/redwood6.c | 27 -
>> ppc/platforms/4xx/redwood6.h | 13
>> ppc/platforms/4xx/sycamore.h | 22 -
>> ppc/platforms/4xx/walnut.h | 22 -
>> ppc/platforms/4xx/xilinx_ml300.h | 12
>> ppc/platforms/83xx/mpc834x_sys.c | 49 +-
>> ppc/platforms/83xx/mpc834x_sys.h | 1
>> ppc/platforms/85xx/mpc8540_ads.c | 57 ++-
>> ppc/platforms/85xx/mpc8560_ads.c | 21 -
>> ppc/platforms/85xx/mpc85xx_ads_common.c | 10
>> ppc/platforms/85xx/mpc85xx_ads_common.h | 1
>> ppc/platforms/85xx/mpc85xx_cds_common.c | 48 +-
>> ppc/platforms/85xx/mpc85xx_cds_common.h | 1
>> ppc/platforms/85xx/sbc8560.c | 19 -
>> ppc/platforms/85xx/sbc85xx.c | 14
>> ppc/platforms/85xx/sbc85xx.h | 1
>> ppc/platforms/85xx/stx_gp3.c | 34 -
>> ppc/platforms/85xx/stx_gp3.h | 1
>> ppc/platforms/bseip.h | 13
>> ppc/platforms/ccm.h | 2
>> ppc/platforms/cpci690.h | 10
>> ppc/platforms/est8260.h | 18
>> ppc/platforms/fads.h | 2
>> ppc/platforms/hdpu.c | 13
>> ppc/platforms/hermes.h | 2
>> ppc/platforms/ip860.h | 2
>> ppc/platforms/ivms8.h | 2
>> ppc/platforms/katana.c | 6
>> ppc/platforms/lantec.h | 2
>> ppc/platforms/lite5200.c | 9
>> ppc/platforms/lwmon.h | 2
>> ppc/platforms/mbx.h | 22 -
>> ppc/platforms/pcu_e.h | 2
>> ppc/platforms/pq2ads.c | 1
>> ppc/platforms/pq2ads.h | 2
>> ppc/platforms/radstone_ppc7d.c | 32 -
>> ppc/platforms/radstone_ppc7d.h | 2
>> ppc/platforms/rpx8260.h | 19 -
>> ppc/platforms/rpxclassic.h | 13
>> ppc/platforms/rpxlite.h | 13
>> ppc/platforms/sandpoint.c | 11
>> ppc/platforms/sandpoint.h | 2
>> ppc/platforms/sbc82xx.c | 6
>> ppc/platforms/sbc82xx.h | 2
>> ppc/platforms/sbs8260.h | 18
>> ppc/platforms/spd8xx.h | 2
>> ppc/platforms/tqm8260.h | 2
>> ppc/platforms/tqm8260_setup.c | 1
>> ppc/platforms/tqm8xx.h | 2
>>
>>
>>
> <snip>
>
> All,
>
> So is this patch going to go in? I haven't seen anyone "push it up".
> The reason I'm asking is that I have a couple patches that I would like
> to push up but they will collide with this one so I need to know if it
> (or a variation thereof) is going to go in or not.
>
> Thanks,
>
> Mark
>
> _______________________________________________
> Linuxppc-embedded mailing list
> Linuxppc-embedded@ozlabs.org
> https://ozlabs.org/mailman/listinfo/linuxppc-embedded
^ permalink raw reply
* [PATCH][3/3] RapidIO support: net driver over messaging
From: Matt Porter @ 2005-06-01 18:25 UTC (permalink / raw)
To: torvalds, akpm, jgarzik; +Cc: netdev, linux-kernel, linuxppc-embedded
In-Reply-To: <20050601111516.B16559@cox.net>
Adds an "Ethernet" driver which sends Ethernet packets over the
standard RapidIO messaging. This depends on the core RIO
patch for mailbox/doorbell access.
Signed-off-by: Matt Porter <mporter@kernel.crashing.org>
Index: drivers/net/Kconfig
===================================================================
--- f0bf7810dbe8c4073832d6c3785364084e9523a7/drivers/net/Kconfig (mode:100644)
+++ 4ed27b6e30a69f314a2ca131e80ac45e2111f245/drivers/net/Kconfig (mode:100644)
@@ -2185,6 +2185,20 @@
tristate "iSeries Virtual Ethernet driver support"
depends on NETDEVICES && PPC_ISERIES
+config RIONET
+ tristate "RapidIO Ethernet over messaging driver support"
+ depends on NETDEVICES && RAPIDIO
+
+config RIONET_TX_SIZE
+ int "Number of outbound queue entries"
+ depends on RIONET
+ default "128"
+
+config RIONET_RX_SIZE
+ int "Number of inbound queue entries"
+ depends on RIONET
+ default "128"
+
config FDDI
bool "FDDI driver support"
depends on NETDEVICES && (PCI || EISA)
Index: drivers/net/Makefile
===================================================================
--- f0bf7810dbe8c4073832d6c3785364084e9523a7/drivers/net/Makefile (mode:100644)
+++ 4ed27b6e30a69f314a2ca131e80ac45e2111f245/drivers/net/Makefile (mode:100644)
@@ -58,6 +58,7 @@
obj-$(CONFIG_VIA_RHINE) += via-rhine.o
obj-$(CONFIG_VIA_VELOCITY) += via-velocity.o
obj-$(CONFIG_ADAPTEC_STARFIRE) += starfire.o
+obj-$(CONFIG_RIONET) += rionet.o
#
# end link order section
Index: drivers/net/rionet.c
===================================================================
--- /dev/null (tree:f0bf7810dbe8c4073832d6c3785364084e9523a7)
+++ 4ed27b6e30a69f314a2ca131e80ac45e2111f245/drivers/net/rionet.c (mode:100644)
@@ -0,0 +1,622 @@
+/*
+ * rionet - Ethernet driver over RapidIO messaging services
+ *
+ * Copyright 2005 MontaVista Software, Inc.
+ * Matt Porter <mporter@kernel.crashing.org>
+ *
+ * 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.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/dma-mapping.h>
+#include <linux/delay.h>
+#include <linux/rio.h>
+#include <linux/rio_drv.h>
+#include <linux/rio_ids.h>
+
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/crc32.h>
+#include <linux/ethtool.h>
+
+#define DRV_NAME "rionet"
+#define DRV_VERSION "0.1"
+#define DRV_AUTHOR "Matt Porter <mporter@kernel.crashing.org>"
+#define DRV_DESC "Ethernet over RapidIO"
+
+MODULE_AUTHOR(DRV_AUTHOR);
+MODULE_DESCRIPTION(DRV_DESC);
+MODULE_LICENSE("GPL");
+
+#define RIONET_DEFAULT_MSGLEVEL 0
+#define RIONET_DOORBELL_JOIN 0x1000
+#define RIONET_DOORBELL_LEAVE 0x1001
+
+#define RIONET_MAILBOX 0
+
+#define RIONET_TX_RING_SIZE CONFIG_RIONET_TX_SIZE
+#define RIONET_RX_RING_SIZE CONFIG_RIONET_RX_SIZE
+
+LIST_HEAD(rionet_peers);
+
+struct rionet_private {
+ struct rio_mport *mport;
+ struct sk_buff *rx_skb[RIONET_RX_RING_SIZE];
+ struct sk_buff *tx_skb[RIONET_TX_RING_SIZE];
+ struct net_device_stats stats;
+ int rx_slot;
+ int tx_slot;
+ int tx_cnt;
+ int ack_slot;
+ spinlock_t lock;
+ u32 msg_enable;
+};
+
+struct rionet_peer {
+ struct list_head node;
+ struct rio_dev *rdev;
+ struct resource *res;
+};
+
+static int rionet_check = 0;
+static int rionet_capable = 1;
+static struct net_device *sndev = NULL;
+
+/*
+ * This is a fast lookup table for for translating TX
+ * Ethernet packets into a destination RIO device. It
+ * could be made into a hash table to save memory depending
+ * on system trade-offs.
+ */
+static struct rio_dev *rionet_active[RIO_MAX_ROUTE_ENTRIES];
+
+#define is_rionet_capable(pef, src_ops, dst_ops) \
+ ((pef & RIO_PEF_INB_MBOX) && \
+ (pef & RIO_PEF_INB_DOORBELL) && \
+ (src_ops & RIO_SRC_OPS_DOORBELL) && \
+ (dst_ops & RIO_DST_OPS_DOORBELL))
+#define dev_rionet_capable(dev) \
+ is_rionet_capable(dev->pef, dev->src_ops, dev->dst_ops)
+
+#define RIONET_MAC_MATCH(x) (*(u32 *)x == 0x00010001)
+#define RIONET_GET_DESTID(x) (*(u16 *)(x + 4))
+
+static struct net_device_stats *rionet_stats(struct net_device *ndev)
+{
+ struct rionet_private *rnet = ndev->priv;
+ return &rnet->stats;
+}
+
+static int rionet_rx_clean(struct net_device *ndev)
+{
+ int i;
+ int error = 0;
+ struct rionet_private *rnet = ndev->priv;
+ void *data;
+
+ i = rnet->rx_slot;
+
+ do {
+ if (!rnet->rx_skb[i]) {
+ rnet->stats.rx_dropped++;
+ continue;
+ }
+
+ if (!(data = rio_get_inb_message(rnet->mport, RIONET_MAILBOX)))
+ break;
+
+ rnet->rx_skb[i]->data = data;
+ skb_put(rnet->rx_skb[i], RIO_MAX_MSG_SIZE);
+ rnet->rx_skb[i]->dev = sndev;
+ rnet->rx_skb[i]->protocol =
+ eth_type_trans(rnet->rx_skb[i], sndev);
+ error = netif_rx(rnet->rx_skb[i]);
+
+ if (error == NET_RX_DROP) {
+ rnet->stats.rx_dropped++;
+ } else if (error == NET_RX_BAD) {
+ if (netif_msg_rx_err(rnet))
+ printk(KERN_WARNING "%s: bad rx packet\n",
+ DRV_NAME);
+ rnet->stats.rx_errors++;
+ } else {
+ rnet->stats.rx_packets++;
+ rnet->stats.rx_bytes += RIO_MAX_MSG_SIZE;
+ }
+
+ } while ((i = (i + 1) % RIONET_RX_RING_SIZE) != rnet->rx_slot);
+
+ return i;
+}
+
+static void rionet_rx_fill(struct net_device *ndev, int end)
+{
+ int i;
+ struct rionet_private *rnet = ndev->priv;
+
+ i = rnet->rx_slot;
+ do {
+ rnet->rx_skb[i] = dev_alloc_skb(RIO_MAX_MSG_SIZE);
+
+ if (!rnet->rx_skb[i])
+ break;
+
+ rio_add_inb_buffer(rnet->mport, RIONET_MAILBOX,
+ rnet->rx_skb[i]->data);
+ } while ((i = (i + 1) % RIONET_RX_RING_SIZE) != end);
+
+ rnet->rx_slot = i;
+}
+
+static int rionet_queue_tx_msg(struct sk_buff *skb, struct net_device *ndev,
+ struct rio_dev *rdev)
+{
+ struct rionet_private *rnet = ndev->priv;
+
+ rio_add_outb_message(rnet->mport, rdev, 0, skb->data, skb->len);
+ rnet->tx_skb[rnet->tx_slot] = skb;
+
+ rnet->stats.tx_packets++;
+ rnet->stats.tx_bytes += skb->len;
+
+ if (++rnet->tx_cnt == RIONET_TX_RING_SIZE)
+ netif_stop_queue(ndev);
+
+ if (++rnet->tx_slot == RIONET_TX_RING_SIZE)
+ rnet->tx_slot = 0;
+
+ if (netif_msg_tx_queued(rnet))
+ printk(KERN_INFO "%s: queued skb %8.8x len %8.8x\n", DRV_NAME,
+ (u32) skb, skb->len);
+
+ return 0;
+}
+
+static int rionet_start_xmit(struct sk_buff *skb, struct net_device *ndev)
+{
+ int i;
+ struct rionet_private *rnet = ndev->priv;
+ struct ethhdr *eth = (struct ethhdr *)skb->data;
+ u16 destid;
+
+ spin_lock_irq(&rnet->lock);
+
+ if ((rnet->tx_cnt + 1) > RIONET_TX_RING_SIZE) {
+ netif_stop_queue(ndev);
+ spin_unlock_irq(&rnet->lock);
+ return -EBUSY;
+ }
+
+ if (eth->h_dest[0] & 0x01) {
+ /*
+ * XXX Need to delay queuing if ring max is reached,
+ * flush additional packets in tx_event() before
+ * awakening the queue. We can easily exceed ring
+ * size with a large number of nodes or even a
+ * small number where the ring is relatively full
+ * on entrance to hard_start_xmit.
+ */
+ for (i = 0; i < RIO_MAX_ROUTE_ENTRIES; i++)
+ if (rionet_active[i])
+ rionet_queue_tx_msg(skb, ndev,
+ rionet_active[i]);
+ } else if (RIONET_MAC_MATCH(eth->h_dest)) {
+ destid = RIONET_GET_DESTID(eth->h_dest);
+ if (rionet_active[destid])
+ rionet_queue_tx_msg(skb, ndev, rionet_active[destid]);
+ }
+
+ spin_unlock_irq(&rnet->lock);
+
+ return 0;
+}
+
+static int rionet_set_mac_address(struct net_device *ndev, void *p)
+{
+ struct sockaddr *addr = p;
+
+ if (!is_valid_ether_addr(addr->sa_data))
+ return -EADDRNOTAVAIL;
+
+ memcpy(ndev->dev_addr, addr->sa_data, ndev->addr_len);
+
+ return 0;
+}
+
+static int rionet_change_mtu(struct net_device *ndev, int new_mtu)
+{
+ struct rionet_private *rnet = ndev->priv;
+
+ if (netif_msg_drv(rnet))
+ printk(KERN_WARNING
+ "%s: rionet_change_mtu(): not implemented\n", DRV_NAME);
+
+ return 0;
+}
+
+static void rionet_set_multicast_list(struct net_device *ndev)
+{
+ struct rionet_private *rnet = ndev->priv;
+
+ if (netif_msg_drv(rnet))
+ printk(KERN_WARNING
+ "%s: rionet_set_multicast_list(): not implemented\n",
+ DRV_NAME);
+}
+
+static void rionet_dbell_event(struct rio_mport *mport, u16 sid, u16 tid,
+ u16 info)
+{
+ struct net_device *ndev = sndev;
+ struct rionet_private *rnet = ndev->priv;
+ struct rionet_peer *peer;
+
+ if (netif_msg_intr(rnet))
+ printk(KERN_INFO "%s: doorbell sid %4.4x tid %4.4x info %4.4x",
+ DRV_NAME, sid, tid, info);
+ if (info == RIONET_DOORBELL_JOIN) {
+ if (!rionet_active[sid]) {
+ list_for_each_entry(peer, &rionet_peers, node) {
+ if (peer->rdev->destid == sid)
+ rionet_active[sid] = peer->rdev;
+ }
+ rio_mport_send_doorbell(mport, sid,
+ RIONET_DOORBELL_JOIN);
+ }
+ } else if (info == RIONET_DOORBELL_LEAVE) {
+ rionet_active[sid] = NULL;
+ } else {
+ if (netif_msg_intr(rnet))
+ printk(KERN_WARNING "%s: unhandled doorbell\n",
+ DRV_NAME);
+ }
+}
+
+static void rionet_inb_msg_event(struct rio_mport *mport, int mbox, int slot)
+{
+ int n;
+ struct net_device *ndev = sndev;
+ struct rionet_private *rnet = (struct rionet_private *)ndev->priv;
+
+ if (netif_msg_intr(rnet))
+ printk(KERN_INFO "%s: inbound message event, mbox %d slot %d\n",
+ DRV_NAME, mbox, slot);
+
+ spin_lock(&rnet->lock);
+ if ((n = rionet_rx_clean(ndev)) != rnet->rx_slot)
+ rionet_rx_fill(ndev, n);
+ spin_unlock(&rnet->lock);
+}
+
+static void rionet_outb_msg_event(struct rio_mport *mport, int mbox, int slot)
+{
+ struct net_device *ndev = sndev;
+ struct rionet_private *rnet = ndev->priv;
+
+ spin_lock(&rnet->lock);
+
+ if (netif_msg_intr(rnet))
+ printk(KERN_INFO
+ "%s: outbound message event, mbox %d slot %d\n",
+ DRV_NAME, mbox, slot);
+
+ while (rnet->tx_cnt && (rnet->ack_slot != slot)) {
+ /* dma unmap single */
+ dev_kfree_skb_irq(rnet->tx_skb[rnet->ack_slot]);
+ rnet->tx_skb[rnet->ack_slot] = NULL;
+ if (++rnet->ack_slot == RIONET_TX_RING_SIZE)
+ rnet->ack_slot = 0;
+ rnet->tx_cnt--;
+ }
+
+ if (rnet->tx_cnt < RIONET_TX_RING_SIZE)
+ netif_wake_queue(ndev);
+
+ spin_unlock(&rnet->lock);
+}
+
+static int rionet_open(struct net_device *ndev)
+{
+ int i, rc = 0;
+ struct rionet_peer *peer, *tmp;
+ u32 pwdcsr;
+ struct rionet_private *rnet = ndev->priv;
+
+ if (netif_msg_ifup(rnet))
+ printk(KERN_INFO "%s: open\n", DRV_NAME);
+
+ if ((rc = rio_request_inb_dbell(rnet->mport,
+ RIONET_DOORBELL_JOIN,
+ RIONET_DOORBELL_LEAVE,
+ rionet_dbell_event)) < 0)
+ goto out;
+
+ if ((rc = rio_request_inb_mbox(rnet->mport,
+ RIONET_MAILBOX,
+ RIONET_RX_RING_SIZE,
+ rionet_inb_msg_event)) < 0)
+ goto out;
+
+ if ((rc = rio_request_outb_mbox(rnet->mport,
+ RIONET_MAILBOX,
+ RIONET_TX_RING_SIZE,
+ rionet_outb_msg_event)) < 0)
+ goto out;
+
+ /* Initialize inbound message ring */
+ for (i = 0; i < RIONET_RX_RING_SIZE; i++)
+ rnet->rx_skb[i] = NULL;
+ rnet->rx_slot = 0;
+ rionet_rx_fill(ndev, 0);
+
+ rnet->tx_slot = 0;
+ rnet->tx_cnt = 0;
+ rnet->ack_slot = 0;
+
+ spin_lock_init(&rnet->lock);
+
+ rnet->msg_enable = RIONET_DEFAULT_MSGLEVEL;
+
+ netif_carrier_on(ndev);
+ netif_start_queue(ndev);
+
+ list_for_each_entry_safe(peer, tmp, &rionet_peers, node) {
+ if (!(peer->res = rio_request_outb_dbell(peer->rdev,
+ RIONET_DOORBELL_JOIN,
+ RIONET_DOORBELL_LEAVE)))
+ {
+ printk(KERN_ERR "%s: error requesting doorbells\n",
+ DRV_NAME);
+ continue;
+ }
+
+ /*
+ * If device has initialized inbound doorbells,
+ * send a join message
+ */
+ rio_read_config_32(peer->rdev, RIO_WRITE_PORT_CSR, &pwdcsr);
+ if (pwdcsr & RIO_DOORBELL_AVAIL)
+ rio_send_doorbell(peer->rdev, RIONET_DOORBELL_JOIN);
+ }
+
+ out:
+ return rc;
+}
+
+static int rionet_close(struct net_device *ndev)
+{
+ struct rionet_private *rnet = (struct rionet_private *)ndev->priv;
+ struct rionet_peer *peer, *tmp;
+ int i;
+
+ if (netif_msg_ifup(rnet))
+ printk(KERN_INFO "%s: close\n", DRV_NAME);
+
+ netif_stop_queue(ndev);
+ netif_carrier_off(ndev);
+
+ for (i = 0; i < RIONET_RX_RING_SIZE; i++)
+ if (rnet->rx_skb[i])
+ kfree_skb(rnet->rx_skb[i]);
+
+ list_for_each_entry_safe(peer, tmp, &rionet_peers, node) {
+ if (rionet_active[peer->rdev->destid]) {
+ rio_send_doorbell(peer->rdev, RIONET_DOORBELL_LEAVE);
+ rionet_active[peer->rdev->destid] = NULL;
+ }
+ rio_release_outb_dbell(peer->rdev, peer->res);
+ }
+
+ rio_release_inb_dbell(rnet->mport, RIONET_DOORBELL_JOIN,
+ RIONET_DOORBELL_LEAVE);
+ rio_release_inb_mbox(rnet->mport, RIONET_MAILBOX);
+ rio_release_outb_mbox(rnet->mport, RIONET_MAILBOX);
+
+ return 0;
+}
+
+static void rionet_remove(struct rio_dev *rdev)
+{
+ struct net_device *ndev = NULL;
+ struct rionet_peer *peer, *tmp;
+
+ unregister_netdev(ndev);
+ kfree(ndev);
+
+ list_for_each_entry_safe(peer, tmp, &rionet_peers, node) {
+ list_del(&peer->node);
+ kfree(peer);
+ }
+}
+
+static int rionet_ioctl(struct net_device *ndev, struct ifreq *rq, int cmd)
+{
+ return -EOPNOTSUPP;
+}
+
+static void rionet_get_drvinfo(struct net_device *ndev,
+ struct ethtool_drvinfo *info)
+{
+ struct rionet_private *rnet = ndev->priv;
+
+ strcpy(info->driver, DRV_NAME);
+ strcpy(info->version, DRV_VERSION);
+ strcpy(info->fw_version, "n/a");
+ sprintf(info->bus_info, "RIO master port %d", rnet->mport->id);
+}
+
+static u32 rionet_get_msglevel(struct net_device *ndev)
+{
+ struct rionet_private *rnet = ndev->priv;
+
+ return rnet->msg_enable;
+}
+
+static void rionet_set_msglevel(struct net_device *ndev, u32 value)
+{
+ struct rionet_private *rnet = ndev->priv;
+
+ rnet->msg_enable = value;
+}
+
+static u32 rionet_get_link(struct net_device *ndev)
+{
+ return netif_carrier_ok(ndev);
+}
+
+static struct ethtool_ops rionet_ethtool_ops = {
+ .get_drvinfo = rionet_get_drvinfo,
+ .get_msglevel = rionet_get_msglevel,
+ .set_msglevel = rionet_set_msglevel,
+ .get_link = rionet_get_link,
+};
+
+static int rionet_setup_netdev(struct rio_mport *mport)
+{
+ int rc = 0;
+ struct net_device *ndev = NULL;
+ struct rionet_private *rnet;
+ u16 device_id;
+
+ /* Allocate our net_device structure */
+ ndev = alloc_etherdev(sizeof(struct rionet_private));
+ if (ndev == NULL) {
+ printk(KERN_INFO "%s: could not allocate ethernet device.\n",
+ DRV_NAME);
+ rc = -ENOMEM;
+ goto out;
+ }
+
+ /*
+ * XXX hack, store point a static at ndev so we can get it...
+ * Perhaps need an array of these that the handler can
+ * index via the mbox number.
+ */
+ sndev = ndev;
+
+ /* Set up private area */
+ rnet = (struct rionet_private *)ndev->priv;
+ rnet->mport = mport;
+
+ /* Set the default MAC address */
+ device_id = rio_local_get_device_id(mport);
+ ndev->dev_addr[0] = 0x00;
+ ndev->dev_addr[1] = 0x01;
+ ndev->dev_addr[2] = 0x00;
+ ndev->dev_addr[3] = 0x01;
+ ndev->dev_addr[4] = device_id >> 8;
+ ndev->dev_addr[5] = device_id & 0xff;
+
+ /* Fill in the driver function table */
+ ndev->open = &rionet_open;
+ ndev->hard_start_xmit = &rionet_start_xmit;
+ ndev->stop = &rionet_close;
+ ndev->get_stats = &rionet_stats;
+ ndev->change_mtu = &rionet_change_mtu;
+ ndev->set_mac_address = &rionet_set_mac_address;
+ ndev->set_multicast_list = &rionet_set_multicast_list;
+ ndev->do_ioctl = &rionet_ioctl;
+ SET_ETHTOOL_OPS(ndev, &rionet_ethtool_ops);
+
+ ndev->mtu = RIO_MAX_MSG_SIZE - 14;
+
+ SET_MODULE_OWNER(ndev);
+
+ rc = register_netdev(ndev);
+ if (rc != 0)
+ goto out;
+
+ printk("%s: %s %s Version %s, MAC %02x:%02x:%02x:%02x:%02x:%02x\n",
+ ndev->name,
+ DRV_NAME,
+ DRV_DESC,
+ DRV_VERSION,
+ ndev->dev_addr[0], ndev->dev_addr[1], ndev->dev_addr[2],
+ ndev->dev_addr[3], ndev->dev_addr[4], ndev->dev_addr[5]);
+
+ out:
+ return rc;
+}
+
+/*
+ * XXX Make multi-net safe
+ */
+static int rionet_probe(struct rio_dev *rdev, const struct rio_device_id *id)
+{
+ int rc = -ENODEV;
+ u32 lpef, lsrc_ops, ldst_ops;
+ struct rionet_peer *peer;
+
+ /* If local device is not rionet capable, give up quickly */
+ if (!rionet_capable)
+ goto out;
+
+ /*
+ * First time through, make sure local device is rionet
+ * capable, setup netdev, and set flags so this is skipped
+ * on later probes
+ */
+ if (!rionet_check) {
+ rio_local_read_config_32(rdev->net->hport, RIO_PEF_CAR, &lpef);
+ rio_local_read_config_32(rdev->net->hport, RIO_SRC_OPS_CAR,
+ &lsrc_ops);
+ rio_local_read_config_32(rdev->net->hport, RIO_DST_OPS_CAR,
+ &ldst_ops);
+ if (!is_rionet_capable(lpef, lsrc_ops, ldst_ops)) {
+ printk(KERN_ERR
+ "%s: local device is not network capable\n",
+ DRV_NAME);
+ rionet_check = 1;
+ rionet_capable = 0;
+ goto out;
+ }
+
+ rc = rionet_setup_netdev(rdev->net->hport);
+ rionet_check = 1;
+ }
+
+ /*
+ * If the remote device has mailbox/doorbell capabilities,
+ * add it to the peer list.
+ */
+ if (dev_rionet_capable(rdev)) {
+ if (!(peer = kmalloc(sizeof(struct rionet_peer), GFP_KERNEL))) {
+ rc = -ENOMEM;
+ goto out;
+ }
+ peer->rdev = rdev;
+ list_add_tail(&peer->node, &rionet_peers);
+ }
+
+ out:
+ return rc;
+}
+
+static struct rio_device_id rionet_id_table[] = {
+ {RIO_DEVICE(RIO_ANY_ID, RIO_ANY_ID)}
+};
+
+static struct rio_driver rionet_driver = {
+ .name = "rionet",
+ .id_table = rionet_id_table,
+ .probe = rionet_probe,
+ .remove = rionet_remove,
+};
+
+static int __init rionet_init(void)
+{
+ return rio_register_driver(&rionet_driver);
+}
+
+static void __exit rionet_exit(void)
+{
+ rio_unregister_driver(&rionet_driver);
+}
+
+module_init(rionet_init);
+module_exit(rionet_exit);
^ permalink raw reply
* [PATCH][2/3] RapidIO support: ppc32
From: Matt Porter @ 2005-06-01 18:15 UTC (permalink / raw)
To: torvalds, akpm; +Cc: linux-kernel, linuxppc-embedded
In-Reply-To: <20050601110836.A16559@cox.net>
Adds PPC32 RIO support. Init code for the MPC85xx RIO ports
and glue for the STx GP3 board to use it.
Signed-off-by: Matt Porter <mporter@kernel.crashing.org>
Index: arch/ppc/Kconfig
===================================================================
--- 750e10a6553cacbd2b92b52fe40afdc8062f4f78/arch/ppc/Kconfig (mode:100644)
+++ f0bf7810dbe8c4073832d6c3785364084e9523a7/arch/ppc/Kconfig (mode:100644)
@@ -1177,6 +1177,14 @@
source "drivers/pcmcia/Kconfig"
+config RAPIDIO
+ bool "RapidIO support" if MPC8540 || MPC8560
+ help
+ If you say Y here, the kernel will include drivers and
+ infrastructure code to support RapidIO interconnect devices.
+
+source "drivers/rio/Kconfig"
+
endmenu
menu "Advanced setup"
Index: arch/ppc/configs/stx_gp3_defconfig
===================================================================
--- 750e10a6553cacbd2b92b52fe40afdc8062f4f78/arch/ppc/configs/stx_gp3_defconfig (mode:100644)
+++ f0bf7810dbe8c4073832d6c3785364084e9523a7/arch/ppc/configs/stx_gp3_defconfig (mode:100644)
@@ -1,7 +1,7 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.11-rc2
-# Wed Jan 26 14:32:58 2005
+# Linux kernel version: 2.6.12-rc4
+# Tue May 24 18:11:04 2005
#
CONFIG_MMU=y
CONFIG_GENERIC_HARDIRQS=y
@@ -11,6 +11,7 @@
CONFIG_PPC=y
CONFIG_PPC32=y
CONFIG_GENERIC_NVRAM=y
+CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y
#
# Code maturity level options
@@ -18,6 +19,7 @@
CONFIG_EXPERIMENTAL=y
CONFIG_CLEAN_COMPILE=y
CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
#
# General setup
@@ -29,7 +31,6 @@
# CONFIG_BSD_PROCESS_ACCT is not set
CONFIG_SYSCTL=y
# CONFIG_AUDIT is not set
-CONFIG_LOG_BUF_SHIFT=14
CONFIG_HOTPLUG=y
CONFIG_KOBJECT_UEVENT=y
# CONFIG_IKCONFIG is not set
@@ -37,6 +38,9 @@
CONFIG_KALLSYMS=y
# CONFIG_KALLSYMS_ALL is not set
# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_BASE_FULL=y
CONFIG_FUTEX=y
CONFIG_EPOLL=y
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
@@ -46,6 +50,7 @@
CONFIG_CC_ALIGN_LOOPS=0
CONFIG_CC_ALIGN_JUMPS=0
# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
#
# Loadable module support
@@ -69,9 +74,11 @@
CONFIG_E500=y
CONFIG_BOOKE=y
CONFIG_FSL_BOOKE=y
+# CONFIG_PHYS_64BIT is not set
# CONFIG_SPE is not set
CONFIG_MATH_EMULATION=y
# CONFIG_CPU_FREQ is not set
+# CONFIG_PM is not set
CONFIG_85xx=y
CONFIG_PPC_INDIRECT_PCI_BE=y
@@ -96,6 +103,7 @@
CONFIG_BINFMT_ELF=y
CONFIG_BINFMT_MISC=m
# CONFIG_CMDLINE_BOOL is not set
+CONFIG_ISA_DMA_API=y
#
# Bus options
@@ -104,15 +112,15 @@
CONFIG_PCI_DOMAINS=y
# CONFIG_PCI_LEGACY_PROC is not set
# CONFIG_PCI_NAMES is not set
+# CONFIG_PCI_DEBUG is not set
#
# PCCARD (PCMCIA/CardBus) support
#
# CONFIG_PCCARD is not set
-
-#
-# PC-card bridges
-#
+CONFIG_RAPIDIO=y
+CONFIG_RAPIDIO_8_BIT_TRANSPORT=y
+CONFIG_RAPIDIO_DISC_TIMEOUT=30
#
# Advanced setup
@@ -152,7 +160,7 @@
CONFIG_PARPORT_PC=m
# CONFIG_PARPORT_PC_FIFO is not set
# CONFIG_PARPORT_PC_SUPERIO is not set
-# CONFIG_PARPORT_OTHER is not set
+# CONFIG_PARPORT_GSC is not set
# CONFIG_PARPORT_1284 is not set
#
@@ -264,7 +272,6 @@
# CONFIG_SCSI_BUSLOGIC is not set
# CONFIG_SCSI_DMX3191D is not set
# CONFIG_SCSI_EATA is not set
-# CONFIG_SCSI_EATA_PIO is not set
# CONFIG_SCSI_FUTURE_DOMAIN is not set
# CONFIG_SCSI_GDTH is not set
# CONFIG_SCSI_IPS is not set
@@ -274,7 +281,6 @@
# CONFIG_SCSI_IMM is not set
# CONFIG_SCSI_SYM53C8XX_2 is not set
# CONFIG_SCSI_IPR is not set
-# CONFIG_SCSI_QLOGIC_ISP is not set
# CONFIG_SCSI_QLOGIC_FC is not set
# CONFIG_SCSI_QLOGIC_1280 is not set
CONFIG_SCSI_QLA2XXX=m
@@ -283,6 +289,7 @@
# CONFIG_SCSI_QLA2300 is not set
# CONFIG_SCSI_QLA2322 is not set
# CONFIG_SCSI_QLA6312 is not set
+# CONFIG_SCSI_LPFC is not set
# CONFIG_SCSI_DC395x is not set
# CONFIG_SCSI_DC390T is not set
# CONFIG_SCSI_NSP32 is not set
@@ -322,7 +329,6 @@
#
CONFIG_PACKET=y
# CONFIG_PACKET_MMAP is not set
-# CONFIG_NETLINK_DEV is not set
CONFIG_UNIX=y
# CONFIG_NET_KEY is not set
CONFIG_INET=y
@@ -431,7 +437,7 @@
#
# Network testing
#
-# CONFIG_NET_PKTGEN is not set
+CONFIG_NET_PKTGEN=y
# CONFIG_NETPOLL is not set
# CONFIG_NET_POLL_CONTROLLER is not set
# CONFIG_HAMRADIO is not set
@@ -499,6 +505,7 @@
# Wan interfaces
#
# CONFIG_WAN is not set
+CONFIG_RIONET=y
# CONFIG_FDDI is not set
# CONFIG_HIPPI is not set
# CONFIG_PLIP is not set
@@ -536,20 +543,6 @@
# CONFIG_INPUT_EVBUG is not set
#
-# Input I/O drivers
-#
-# CONFIG_GAMEPORT is not set
-CONFIG_SOUND_GAMEPORT=y
-CONFIG_SERIO=y
-CONFIG_SERIO_I8042=y
-CONFIG_SERIO_SERPORT=y
-# CONFIG_SERIO_CT82C710 is not set
-# CONFIG_SERIO_PARKBD is not set
-# CONFIG_SERIO_PCIPS2 is not set
-CONFIG_SERIO_LIBPS2=y
-# CONFIG_SERIO_RAW is not set
-
-#
# Input Device Drivers
#
CONFIG_INPUT_KEYBOARD=y
@@ -567,6 +560,19 @@
# CONFIG_INPUT_MISC is not set
#
+# Hardware I/O ports
+#
+CONFIG_SERIO=y
+CONFIG_SERIO_I8042=y
+CONFIG_SERIO_SERPORT=y
+# CONFIG_SERIO_PARKBD is not set
+# CONFIG_SERIO_PCIPS2 is not set
+CONFIG_SERIO_LIBPS2=y
+# CONFIG_SERIO_RAW is not set
+# CONFIG_GAMEPORT is not set
+CONFIG_SOUND_GAMEPORT=y
+
+#
# Character devices
#
# CONFIG_VT is not set
@@ -590,6 +596,7 @@
# CONFIG_SERIAL_CPM_SCC4 is not set
# CONFIG_SERIAL_CPM_SMC1 is not set
# CONFIG_SERIAL_CPM_SMC2 is not set
+# CONFIG_SERIAL_JSM is not set
CONFIG_UNIX98_PTYS=y
CONFIG_LEGACY_PTYS=y
CONFIG_LEGACY_PTY_COUNT=256
@@ -626,6 +633,11 @@
# CONFIG_RAW_DRIVER is not set
#
+# TPM devices
+#
+# CONFIG_TCG_TPM is not set
+
+#
# I2C support
#
CONFIG_I2C=m
@@ -648,12 +660,12 @@
# CONFIG_I2C_AMD8111 is not set
# CONFIG_I2C_I801 is not set
# CONFIG_I2C_I810 is not set
+# CONFIG_I2C_PIIX4 is not set
# CONFIG_I2C_ISA is not set
# CONFIG_I2C_MPC is not set
# CONFIG_I2C_NFORCE2 is not set
# CONFIG_I2C_PARPORT is not set
# CONFIG_I2C_PARPORT_LIGHT is not set
-# CONFIG_I2C_PIIX4 is not set
# CONFIG_I2C_PROSAVAGE is not set
# CONFIG_I2C_SAVAGE4 is not set
# CONFIG_SCx200_ACB is not set
@@ -677,7 +689,9 @@
# CONFIG_SENSORS_ASB100 is not set
# CONFIG_SENSORS_DS1621 is not set
# CONFIG_SENSORS_FSCHER is not set
+# CONFIG_SENSORS_FSCPOS is not set
# CONFIG_SENSORS_GL518SM is not set
+# CONFIG_SENSORS_GL520SM is not set
# CONFIG_SENSORS_IT87 is not set
# CONFIG_SENSORS_LM63 is not set
# CONFIG_SENSORS_LM75 is not set
@@ -688,9 +702,11 @@
# CONFIG_SENSORS_LM85 is not set
# CONFIG_SENSORS_LM87 is not set
# CONFIG_SENSORS_LM90 is not set
+# CONFIG_SENSORS_LM92 is not set
# CONFIG_SENSORS_MAX1619 is not set
# CONFIG_SENSORS_PC87360 is not set
# CONFIG_SENSORS_SMSC47B397 is not set
+# CONFIG_SENSORS_SIS5595 is not set
# CONFIG_SENSORS_SMSC47M1 is not set
# CONFIG_SENSORS_VIA686A is not set
# CONFIG_SENSORS_W83781D is not set
@@ -700,10 +716,12 @@
#
# Other I2C Chip support
#
+# CONFIG_SENSORS_DS1337 is not set
# CONFIG_SENSORS_EEPROM is not set
# CONFIG_SENSORS_PCF8574 is not set
# CONFIG_SENSORS_PCF8591 is not set
# CONFIG_SENSORS_RTC8564 is not set
+# CONFIG_SENSORS_M41T00 is not set
# CONFIG_I2C_DEBUG_CORE is not set
# CONFIG_I2C_DEBUG_ALGO is not set
# CONFIG_I2C_DEBUG_BUS is not set
@@ -732,7 +750,6 @@
# Graphics support
#
# CONFIG_FB is not set
-# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
#
# Sound
@@ -752,13 +769,9 @@
#
# USB support
#
-# CONFIG_USB is not set
CONFIG_USB_ARCH_HAS_HCD=y
CONFIG_USB_ARCH_HAS_OHCI=y
-
-#
-# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' may also be needed; see USB_STORAGE Help for more information
-#
+# CONFIG_USB is not set
#
# USB Gadget Support
@@ -789,6 +802,10 @@
CONFIG_FS_MBCACHE=y
# CONFIG_REISERFS_FS is not set
# CONFIG_JFS_FS is not set
+
+#
+# XFS support
+#
# CONFIG_XFS_FS is not set
# CONFIG_MINIX_FS is not set
# CONFIG_ROMFS_FS is not set
@@ -859,7 +876,6 @@
CONFIG_ROOT_NFS=y
CONFIG_LOCKD=y
CONFIG_LOCKD_V4=y
-# CONFIG_EXPORTFS is not set
CONFIG_SUNRPC=y
# CONFIG_RPCSEC_GSS_KRB5 is not set
# CONFIG_RPCSEC_GSS_SPKM3 is not set
@@ -942,8 +958,10 @@
#
# Kernel hacking
#
+# CONFIG_PRINTK_TIME is not set
CONFIG_DEBUG_KERNEL=y
# CONFIG_MAGIC_SYSRQ is not set
+CONFIG_LOG_BUF_SHIFT=14
# CONFIG_SCHEDSTATS is not set
# CONFIG_DEBUG_SLAB is not set
# CONFIG_DEBUG_SPINLOCK is not set
Index: arch/ppc/kernel/Makefile
===================================================================
--- 750e10a6553cacbd2b92b52fe40afdc8062f4f78/arch/ppc/kernel/Makefile (mode:100644)
+++ f0bf7810dbe8c4073832d6c3785364084e9523a7/arch/ppc/kernel/Makefile (mode:100644)
@@ -22,6 +22,7 @@
obj-$(CONFIG_MODULES) += module.o ppc_ksyms.o
obj-$(CONFIG_NOT_COHERENT_CACHE) += dma-mapping.o
obj-$(CONFIG_PCI) += pci.o
+obj-$(CONFIG_RAPIDIO) += rio.o
obj-$(CONFIG_KGDB) += ppc-stub.o
obj-$(CONFIG_SMP) += smp.o smp-tbsync.o
obj-$(CONFIG_TAU) += temp.o
Index: arch/ppc/kernel/rio.c
===================================================================
--- /dev/null (tree:750e10a6553cacbd2b92b52fe40afdc8062f4f78)
+++ f0bf7810dbe8c4073832d6c3785364084e9523a7/arch/ppc/kernel/rio.c (mode:100644)
@@ -0,0 +1,52 @@
+/*
+ * RapidIO PPC32 support
+ *
+ * Copyright 2005 MontaVista Software, Inc.
+ * Matt Porter <mporter@kernel.crashing.org>
+ *
+ * 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.
+ */
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/rio.h>
+
+#include <asm/rio.h>
+
+/**
+ * platform_rio_init - Do platform specific RIO init
+ *
+ * Any platform specific initialization of RapdIO
+ * hardware is done here as well as registration
+ * of any active master ports in the system.
+ */
+void __attribute__ ((weak))
+ platform_rio_init(void)
+{
+ printk(KERN_WARNING "RIO: No platform_rio_init() present\n");
+}
+
+/**
+ * ppc_rio_init - Do PPC32 RIO init
+ *
+ * Calls platform-specific RIO init code and then calls
+ * rio_init_mports() to initialize any master ports that
+ * have been registered with the RIO subsystem.
+ */
+static int __init ppc_rio_init(void)
+{
+ printk(KERN_INFO "RIO: RapidIO init\n");
+
+ /* Platform specific initialization */
+ platform_rio_init();
+
+ /* Enumerate all registered ports */
+ rio_init_mports();
+
+ return 0;
+}
+
+subsys_initcall(ppc_rio_init);
Index: arch/ppc/platforms/85xx/stx_gp3.c
===================================================================
--- 750e10a6553cacbd2b92b52fe40afdc8062f4f78/arch/ppc/platforms/85xx/stx_gp3.c (mode:100644)
+++ f0bf7810dbe8c4073832d6c3785364084e9523a7/arch/ppc/platforms/85xx/stx_gp3.c (mode:100644)
@@ -38,6 +38,7 @@
#include <linux/module.h>
#include <linux/fsl_devices.h>
#include <linux/interrupt.h>
+#include <linux/rio.h>
#include <asm/system.h>
#include <asm/pgtable.h>
@@ -59,6 +60,7 @@
#include <syslib/cpm2_pic.h>
#include <syslib/ppc85xx_common.h>
+#include <syslib/ppc85xx_rio.h>
extern void cpm2_reset(void);
@@ -200,7 +202,6 @@
static void __init
gp3_init_IRQ(void)
{
- int i;
bd_t *binfo = (bd_t *) __res;
/*
@@ -297,6 +298,18 @@
}
#endif /* CONFIG_PCI */
+#ifdef CONFIG_RAPIDIO
+void
+platform_rio_init(void)
+{
+ /*
+ * The STx firmware configures the RapidIO Local Access Window
+ * at 0xc0000000 with a size of 512MB.
+ */
+ mpc85xx_rio_setup(0xc0000000, 0x20000000);
+}
+#endif /* CONFIG_RAPIDIO */
+
void __init
platform_init(unsigned long r3, unsigned long r4, unsigned long r5,
unsigned long r6, unsigned long r7)
Index: arch/ppc/syslib/Makefile
===================================================================
--- 750e10a6553cacbd2b92b52fe40afdc8062f4f78/arch/ppc/syslib/Makefile (mode:100644)
+++ f0bf7810dbe8c4073832d6c3785364084e9523a7/arch/ppc/syslib/Makefile (mode:100644)
@@ -101,6 +101,7 @@
mpc85xx_devices.o
ifeq ($(CONFIG_85xx),y)
obj-$(CONFIG_PCI) += indirect_pci.o pci_auto.o
+obj-$(CONFIG_RAPIDIO) += ppc85xx_rio.o
endif
obj-$(CONFIG_83xx) += ipic.o ppc83xx_setup.o ppc_sys.o \
mpc83xx_sys.o mpc83xx_devices.o
Index: arch/ppc/syslib/ppc85xx_rio.c
===================================================================
--- /dev/null (tree:750e10a6553cacbd2b92b52fe40afdc8062f4f78)
+++ f0bf7810dbe8c4073832d6c3785364084e9523a7/arch/ppc/syslib/ppc85xx_rio.c (mode:100644)
@@ -0,0 +1,867 @@
+/*
+ * MPC85xx RapidIO support
+ *
+ * Copyright 2005 MontaVista Software, Inc.
+ * Matt Porter <mporter@kernel.crashing.org>
+ *
+ * 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.
+ */
+
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/dma-mapping.h>
+#include <linux/interrupt.h>
+#include <linux/rio.h>
+#include <linux/rio_drv.h>
+
+#include <asm/io.h>
+
+#define RIO_REGS_BASE (CCSRBAR + 0xc0000)
+#define RIO_ATMU_REGS_OFFSET 0x10c00
+#define RIO_MSG_REGS_OFFSET 0x11000
+#define RIO_MAINT_WIN_SIZE 0x400000
+#define RIO_DBELL_WIN_SIZE 0x1000
+
+#define RIO_MSG_OMR_MUI 0x00000002
+#define RIO_MSG_OSR_TE 0x00000080
+#define RIO_MSG_OSR_QOI 0x00000020
+#define RIO_MSG_OSR_QFI 0x00000010
+#define RIO_MSG_OSR_MUB 0x00000004
+#define RIO_MSG_OSR_EOMI 0x00000002
+#define RIO_MSG_OSR_QEI 0x00000001
+
+#define RIO_MSG_IMR_MI 0x00000002
+#define RIO_MSG_ISR_TE 0x00000080
+#define RIO_MSG_ISR_QFI 0x00000010
+#define RIO_MSG_ISR_DIQI 0x00000001
+
+#define RIO_MSG_DESC_SIZE 32
+#define RIO_MIN_TX_RING_SIZE 2
+#define RIO_MAX_TX_RING_SIZE 2048
+#define RIO_MIN_RX_RING_SIZE 2
+#define RIO_MAX_RX_RING_SIZE 2048
+
+#define DOORBELL_DMR_DI 0x00000002
+#define DOORBELL_DSR_TE 0x00000080
+#define DOORBELL_DSR_QFI 0x00000010
+#define DOORBELL_DSR_DIQI 0x00000001
+#define DOORBELL_TID_OFFSET 0x03
+#define DOORBELL_SID_OFFSET 0x05
+#define DOORBELL_INFO_OFFSET 0x06
+
+#define DOORBELL_MESSAGE_SIZE 0x08
+#define DBELL_SID(x) (*(u8 *)(x + DOORBELL_SID_OFFSET))
+#define DBELL_TID(x) (*(u8 *)(x + DOORBELL_TID_OFFSET))
+#define DBELL_INF(x) (*(u16 *)(x + DOORBELL_INFO_OFFSET))
+
+#define is_power_of_2(x) (((x) & ((x) - 1)) == 0)
+
+struct rio_atmu_regs {
+ u32 rowtar;
+ u32 pad1;
+ u32 rowbar;
+ u32 pad2;
+ u32 rowar;
+ u32 pad3[3];
+};
+
+struct rio_msg_regs {
+ u32 omr;
+ u32 osr;
+ u32 pad1;
+ u32 odqdpar;
+ u32 pad2;
+ u32 osar;
+ u32 odpr;
+ u32 odatr;
+ u32 odcr;
+ u32 pad3;
+ u32 odqepar;
+ u32 pad4[13];
+ u32 imr;
+ u32 isr;
+ u32 pad5;
+ u32 ifqdpar;
+ u32 pad6;
+ u32 ifqepar;
+ u32 pad7[250];
+ u32 dmr;
+ u32 dsr;
+ u32 pad8;
+ u32 dqdpar;
+ u32 pad9;
+ u32 dqepar;
+ u32 pad10[26];
+ u32 pwmr;
+ u32 pwsr;
+ u32 pad11;
+ u32 pwqbar;
+};
+
+struct rio_tx_desc {
+ u32 res1;
+ u32 saddr;
+ u32 dport;
+ u32 dattr;
+ u32 res2;
+ u32 res3;
+ u32 dwcnt;
+ u32 res4;
+};
+
+static u32 regs_win;
+static struct rio_atmu_regs *atmu_regs;
+static struct rio_atmu_regs *maint_atmu_regs;
+static struct rio_atmu_regs *dbell_atmu_regs;
+static u32 dbell_win;
+static u32 maint_win;
+static struct rio_msg_regs *msg_regs;
+
+static struct rio_dbell_ring {
+ void *virt;
+ dma_addr_t phys;
+} dbell_ring;
+
+static struct rio_msg_tx_ring {
+ void *virt;
+ dma_addr_t phys;
+ void *virt_buffer[RIO_MAX_TX_RING_SIZE];
+ dma_addr_t phys_buffer[RIO_MAX_TX_RING_SIZE];
+ int tx_slot;
+ int size;
+} msg_tx_ring;
+
+static struct rio_msg_rx_ring {
+ void *virt;
+ dma_addr_t phys;
+ void *virt_buffer[RIO_MAX_RX_RING_SIZE];
+ int rx_slot;
+ int size;
+} msg_rx_ring;
+
+/**
+ * mpc85xx_rio_doorbell_send - Send a MPC85xx doorbell message
+ * @index: ID of RapidIO interface
+ * @destid: Destination ID of target device
+ * @data: 16-bit info field of RapidIO doorbell message
+ *
+ * Sends a MPC85xx doorbell message. Returns %0 on success or
+ * %-EINVAL on failure.
+ */
+static int mpc85xx_rio_doorbell_send(int index, u16 destid, u16 data)
+{
+ pr_debug("mpc85xx_doorbell_send: index %d destid %4.4x data %4.4x\n",
+ index, destid, data);
+ out_be32((void *)&dbell_atmu_regs->rowtar, destid << 22);
+ out_be16((void *)(dbell_win), data);
+
+ return 0;
+}
+
+/**
+ * mpc85xx_local_config_read - Generate a MPC85xx local config space read
+ * @index: ID of RapdiIO interface
+ * @offset: Offset into configuration space
+ * @len: Length (in bytes) of the maintenance transaction
+ * @data: Value to be read into
+ *
+ * Generates a MPC85xx local configuration space read. Returns %0 on
+ * success or %-EINVAL on failure.
+ */
+static int mpc85xx_local_config_read(int index, u32 offset, int len, u32 * data)
+{
+ pr_debug("mpc85xx_local_config_read: index %d offset %8.8x\n", index,
+ offset);
+ *data = in_be32((void *)(regs_win + offset));
+
+ return 0;
+}
+
+/**
+ * mpc85xx_local_config_write - Generate a MPC85xx local config space write
+ * @index: ID of RapdiIO interface
+ * @offset: Offset into configuration space
+ * @len: Length (in bytes) of the maintenance transaction
+ * @data: Value to be written
+ *
+ * Generates a MPC85xx local configuration space write. Returns %0 on
+ * success or %-EINVAL on failure.
+ */
+static int mpc85xx_local_config_write(int index, u32 offset, int len, u32 data)
+{
+ pr_debug
+ ("mpc85xx_local_config_write: index %d offset %8.8x data %8.8x\n",
+ index, offset, data);
+ out_be32((void *)(regs_win + offset), data);
+
+ return 0;
+}
+
+/**
+ * mpc85xx_rio_config_read - Generate a MPC85xx read maintenance transaction
+ * @index: ID of RapdiIO interface
+ * @destid: Destination ID of transaction
+ * @hopcount: Number of hops to target device
+ * @offset: Offset into configuration space
+ * @len: Length (in bytes) of the maintenance transaction
+ * @val: Location to be read into
+ *
+ * Generates a MPC85xx read maintenance transaction. Returns %0 on
+ * success or %-EINVAL on failure.
+ */
+static int
+mpc85xx_rio_config_read(int index, u16 destid, u8 hopcount, u32 offset, int len,
+ u32 * val)
+{
+ u8 *data;
+
+ pr_debug
+ ("mpc85xx_rio_config_read: index %d destid %d hopcount %d offset %8.8x len %d\n",
+ index, destid, hopcount, offset, len);
+ out_be32((void *)&maint_atmu_regs->rowtar,
+ (destid << 22) | (hopcount << 12) | ((offset & ~0x3) >> 9));
+
+ data = (u8 *) maint_win + offset;
+ switch (len) {
+ case 1:
+ *val = in_8((u8 *) data);
+ break;
+ case 2:
+ *val = in_be16((u16 *) data);
+ break;
+ default:
+ *val = in_be32((u32 *) data);
+ break;
+ }
+
+ return 0;
+}
+
+/**
+ * mpc85xx_rio_config_write - Generate a MPC85xx write maintenance transaction
+ * @index: ID of RapdiIO interface
+ * @destid: Destination ID of transaction
+ * @hopcount: Number of hops to target device
+ * @offset: Offset into configuration space
+ * @len: Length (in bytes) of the maintenance transaction
+ * @val: Value to be written
+ *
+ * Generates an MPC85xx write maintenance transaction. Returns %0 on
+ * success or %-EINVAL on failure.
+ */
+static int
+mpc85xx_rio_config_write(int index, u16 destid, u8 hopcount, u32 offset,
+ int len, u32 val)
+{
+ u8 *data;
+ pr_debug
+ ("mpc85xx_rio_config_write: index %d destid %d hopcount %d offset %8.8x len %d val %8.8x\n",
+ index, destid, hopcount, offset, len, val);
+ out_be32((void *)&maint_atmu_regs->rowtar,
+ (destid << 22) | (hopcount << 12) | ((offset & ~0x3) >> 9));
+
+ data = (u8 *) maint_win + offset;
+ switch (len) {
+ case 1:
+ out_8((u8 *) data, val);
+ break;
+ case 2:
+ out_be16((u16 *) data, val);
+ break;
+ default:
+ out_be32((u32 *) data, val);
+ break;
+ }
+
+ return 0;
+}
+
+/**
+ * rio_hw_add_outb_message - Add message to the MPC85xx outbound message queue
+ * @mport: Master port with outbound message queue
+ * @rdev: Target of outbound message
+ * @mbox: Outbound mailbox
+ * @buffer: Message to add to outbound queue
+ * @len: Length of message
+ *
+ * Adds the @buffer message to the MPC85xx outbound message queue. Returns
+ * %0 on success or %-EINVAL on failure.
+ */
+int
+rio_hw_add_outb_message(struct rio_mport *mport, struct rio_dev *rdev, int mbox,
+ void *buffer, size_t len)
+{
+ u32 omr;
+ struct rio_tx_desc *desc =
+ (struct rio_tx_desc *)msg_tx_ring.virt + msg_tx_ring.tx_slot;
+ int ret = 0;
+
+ pr_debug(KERN_INFO
+ "RIO: rio_hw_add_outb_message(): destid %4.4x mbox %d buffer %8.8x len %8.8x\n",
+ rdev->destid, mbox, (int)buffer, len);
+
+ if ((len < 8) || (len > RIO_MAX_MSG_SIZE)) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ /* Copy and clear rest of buffer */
+ memcpy(msg_tx_ring.virt_buffer[msg_tx_ring.tx_slot], buffer, len);
+ if (len < (RIO_MAX_MSG_SIZE - 4))
+ memset((void *)((u32) msg_tx_ring.
+ virt_buffer[msg_tx_ring.tx_slot] + len), 0,
+ RIO_MAX_MSG_SIZE - len);
+
+ /* Set mbox field for message */
+ desc->dport = mbox & 0x3;
+
+ /* Enable EOMI interrupt, set priority, and set destid */
+ desc->dattr = 0x28000000 | (rdev->destid << 2);
+
+ /* Set transfer size aligned to next power of 2 (in double words) */
+ desc->dwcnt = is_power_of_2(len) ? len : 1 << get_bitmask_order(len);
+
+ /* Set snooping and source buffer address */
+ desc->saddr = 0x00000004 | msg_tx_ring.phys_buffer[msg_tx_ring.tx_slot];
+
+ /* Increment enqueue pointer */
+ omr = in_be32((void *)&msg_regs->omr);
+ out_be32((void *)&msg_regs->omr, omr | RIO_MSG_OMR_MUI);
+
+ /* Go to next descriptor */
+ if (++msg_tx_ring.tx_slot == msg_tx_ring.size)
+ msg_tx_ring.tx_slot = 0;
+
+ out:
+ return ret;
+}
+
+EXPORT_SYMBOL(rio_hw_add_outb_message);
+
+/**
+ * mpc85xx_rio_tx_handler - MPC85xx outbound message interrupt handler
+ * @irq: Linux interrupt number
+ * @dev_instance: Pointer to interrupt-specific data
+ * @regs: Register context
+ *
+ * Handles outbound message interrupts. Executes a register outbound
+ * mailbox event handler and acks the interrupt occurence.
+ */
+static irqreturn_t
+mpc85xx_rio_tx_handler(int irq, void *dev_instance, struct pt_regs *regs)
+{
+ int osr;
+ struct rio_mport *port = (struct rio_mport *)dev_instance;
+
+ osr = in_be32((void *)&msg_regs->osr);
+
+ if (osr & RIO_MSG_OSR_TE) {
+ printk(KERN_INFO "RIO: outbound message transmission error\n");
+ out_be32((void *)&msg_regs->osr, RIO_MSG_OSR_TE);
+ goto out;
+ }
+
+ if (osr & RIO_MSG_OSR_QOI) {
+ printk(KERN_INFO "RIO: outbound message queue overflow\n");
+ out_be32((void *)&msg_regs->osr, RIO_MSG_OSR_QOI);
+ goto out;
+ }
+
+ if (osr & RIO_MSG_OSR_EOMI) {
+ u32 dqp = in_be32((void *)&msg_regs->odqdpar);
+ int slot = (dqp - msg_tx_ring.phys) >> 5;
+ port->outb_msg[0].mcback(port, -1, slot);
+
+ /* Ack the end-of-message interrupt */
+ out_be32((void *)&msg_regs->osr, RIO_MSG_OSR_EOMI);
+ }
+
+ out:
+ return IRQ_HANDLED;
+}
+
+/**
+ * rio_open_outb_mbox - Initialize MPC85xx outbound mailbox
+ * @mport: Master port implementing the outbound message unit
+ * @mbox: Mailbox to open
+ * @entries: Number of entries in the outbound mailbox ring
+ *
+ * Initializes buffer ring, request the outbound message interrupt,
+ * and enables the outbound message unit. Returns %0 on success or
+ * %-EINVAL on failure.
+ */
+int rio_open_outb_mbox(struct rio_mport *mport, int mbox, int entries)
+{
+ int i, rc = 0;
+
+ if ((entries < RIO_MIN_TX_RING_SIZE) ||
+ (entries > RIO_MAX_TX_RING_SIZE) || (!is_power_of_2(entries))) {
+ rc = -EINVAL;
+ goto out;
+ }
+
+ /* Initialize shadow copy ring */
+ msg_tx_ring.size = entries;
+
+ for (i = 0; i < msg_tx_ring.size; i++) {
+ msg_tx_ring.virt_buffer[i] =
+ (void *)__get_free_page(GFP_KERNEL);
+ msg_tx_ring.phys_buffer[i] =
+ (dma_addr_t) __pa(msg_tx_ring.virt_buffer[i]);
+ }
+
+ /* Initialize outbound message descriptor ring */
+ msg_tx_ring.virt = dma_alloc_coherent(NULL,
+ msg_tx_ring.size *
+ RIO_MSG_DESC_SIZE,
+ &msg_tx_ring.phys, GFP_KERNEL);
+ memset(msg_tx_ring.virt, 0, msg_tx_ring.size * RIO_MSG_DESC_SIZE);
+ msg_tx_ring.tx_slot = 0;
+
+ /* Point dequeue/enqueue pointers at first entry in ring */
+ out_be32((void *)&msg_regs->odqdpar, msg_tx_ring.phys);
+ out_be32((void *)&msg_regs->odqepar, msg_tx_ring.phys);
+
+ /* Configure for snooping */
+ out_be32((void *)&msg_regs->osar, 0x00000004);
+
+ /* Clear interrupt status */
+ out_be32((void *)&msg_regs->osr, 0x000000b3);
+
+ /* Hook up outbound message handler */
+ request_irq(MPC85xx_IRQ_RIO_TX, mpc85xx_rio_tx_handler, 0, "msg_tx",
+ (void *)mport);
+
+ /*
+ * Configure outbound message unit
+ * Snooping
+ * Interrupts (all enabled, except QEIE)
+ * Chaining mode
+ * Disable
+ */
+ out_be32((void *)&msg_regs->omr, 0x00100220);
+
+ /* Set number of entries */
+ out_be32((void *)&msg_regs->omr,
+ in_be32((void *)&msg_regs->omr) |
+ ((get_bitmask_order(entries) - 2) << 12));
+
+ /* Now enable the unit */
+ out_be32((void *)&msg_regs->omr, in_be32((void *)&msg_regs->omr) | 0x1);
+
+ out:
+ return rc;
+}
+
+/**
+ * rio_close_outb_mbox - Shut down MPC85xx outbound mailbox
+ * @mport: Master port implementing the outbound message unit
+ * @mbox: Mailbox to close
+ *
+ * Disables the outbound message unit, free all buffers, and
+ * frees the outbound message interrupt.
+ */
+void rio_close_outb_mbox(struct rio_mport *mport, int mbox)
+{
+ /* Disable inbound message unit */
+ out_be32((void *)&msg_regs->omr, 0);
+
+ /* Free ring */
+ dma_free_coherent(NULL, msg_tx_ring.size * RIO_MSG_DESC_SIZE,
+ msg_tx_ring.virt, msg_tx_ring.phys);
+
+ /* Free interrupt */
+ free_irq(MPC85xx_IRQ_RIO_TX, (void *)mport);
+}
+
+/**
+ * mpc85xx_rio_rx_handler - MPC85xx inbound message interrupt handler
+ * @irq: Linux interrupt number
+ * @dev_instance: Pointer to interrupt-specific data
+ * @regs: Register context
+ *
+ * Handles inbound message interrupts. Executes a registered inbound
+ * mailbox event handler and acks the interrupt occurence.
+ */
+static irqreturn_t
+mpc85xx_rio_rx_handler(int irq, void *dev_instance, struct pt_regs *regs)
+{
+ int isr;
+ struct rio_mport *port = (struct rio_mport *)dev_instance;
+
+ isr = in_be32((void *)&msg_regs->isr);
+
+ if (isr & RIO_MSG_ISR_TE) {
+ printk(KERN_INFO "RIO: inbound message reception error\n");
+ out_be32((void *)&msg_regs->isr, RIO_MSG_ISR_TE);
+ goto out;
+ }
+
+ /* XXX Need to check/dispatch until queue empty */
+ if (isr & RIO_MSG_ISR_DIQI) {
+ /*
+ * We implement *only* mailbox 0, but can receive messages
+ * for any mailbox/letter to that mailbox destination. So,
+ * make the callback with an unknown/invalid mailbox number
+ * argument.
+ */
+ port->inb_msg[0].mcback(port, -1, -1);
+
+ /* Ack the queueing interrupt */
+ out_be32((void *)&msg_regs->isr, RIO_MSG_ISR_DIQI);
+ }
+
+ out:
+ return IRQ_HANDLED;
+}
+
+/**
+ * rio_open_inb_mbox - Initialize MPC85xx inbound mailbox
+ * @mport: Master port implementing the inbound message unit
+ * @mbox: Mailbox to open
+ * @entries: Number of entries in the inbound mailbox ring
+ *
+ * Initializes buffer ring, request the inbound message interrupt,
+ * and enables the inbound message unit. Returns %0 on success
+ * or %-EINVAL on failure.
+ */
+int rio_open_inb_mbox(struct rio_mport *mport, int mbox, int entries)
+{
+ int i, rc = 0;
+
+ if ((entries < RIO_MIN_RX_RING_SIZE) ||
+ (entries > RIO_MAX_RX_RING_SIZE) || (!is_power_of_2(entries))) {
+ rc = -EINVAL;
+ goto out;
+ }
+
+ /* Initialize client buffer ring */
+ msg_rx_ring.size = entries;
+ msg_rx_ring.rx_slot = 0;
+ for (i = 0; i < msg_rx_ring.size; i++)
+ msg_rx_ring.virt_buffer[i] = NULL;
+
+ /* Initialize inbound message ring */
+ msg_rx_ring.virt = dma_alloc_coherent(NULL,
+ msg_rx_ring.size *
+ RIO_MAX_MSG_SIZE,
+ &msg_rx_ring.phys, GFP_KERNEL);
+
+ /* Point dequeue/enqueue pointers at first entry in ring */
+ out_be32((void *)&msg_regs->ifqdpar, (u32) msg_rx_ring.phys);
+ out_be32((void *)&msg_regs->ifqepar, (u32) msg_rx_ring.phys);
+
+ /* Clear interrupt status */
+ out_be32((void *)&msg_regs->isr, 0x00000091);
+
+ /* Hook up inbound message handler */
+ request_irq(MPC85xx_IRQ_RIO_RX, mpc85xx_rio_rx_handler, 0, "msg_rx",
+ (void *)mport);
+
+ /*
+ * Configure inbound message unit:
+ * Snooping
+ * 4KB max message size
+ * Unmask all interrupt sources
+ * Disable
+ */
+ out_be32((void *)&msg_regs->imr, 0x001b0060);
+
+ /* Set number of queue entries */
+ out_be32((void *)&msg_regs->imr,
+ in_be32((void *)&msg_regs->imr) |
+ ((get_bitmask_order(entries) - 2) << 12));
+
+ /* Now enable the unit */
+ out_be32((void *)&msg_regs->imr, in_be32((void *)&msg_regs->imr) | 0x1);
+
+ out:
+ return rc;
+}
+
+/**
+ * rio_close_inb_mbox - Shut down MPC85xx inbound mailbox
+ * @mport: Master port implementing the inbound message unit
+ * @mbox: Mailbox to close
+ *
+ * Disables the inbound message unit, free all buffers, and
+ * frees the inbound message interrupt.
+ */
+void rio_close_inb_mbox(struct rio_mport *mport, int mbox)
+{
+ /* Disable inbound message unit */
+ out_be32((void *)&msg_regs->imr, 0);
+
+ /* Free ring */
+ dma_free_coherent(NULL, msg_rx_ring.size * RIO_MAX_MSG_SIZE,
+ msg_rx_ring.virt, msg_rx_ring.phys);
+
+ /* Free interrupt */
+ free_irq(MPC85xx_IRQ_RIO_RX, (void *)mport);
+}
+
+/**
+ * rio_hw_add_inb_buffer - Add buffer to the MPC85xx inbound message queue
+ * @mport: Master port implementing the inbound message unit
+ * @mbox: Inbound mailbox number
+ * @buf: Buffer to add to inbound queue
+ *
+ * Adds the @buf buffer to the MPC85xx inbound message queue. Returns
+ * %0 on success or %-EINVAL on failure.
+ */
+int rio_hw_add_inb_buffer(struct rio_mport *mport, int mbox, void *buf)
+{
+ int rc = 0;
+
+ pr_debug("RIO: rio_hw_add_inb_buffer(), msg_rx_ring.rx_slot %d\n",
+ msg_rx_ring.rx_slot);
+
+ if (msg_rx_ring.virt_buffer[msg_rx_ring.rx_slot]) {
+ printk(KERN_ERR
+ "RIO: error adding inbound buffer %d, buffer exists\n",
+ msg_rx_ring.rx_slot);
+ rc = -EINVAL;
+ goto out;
+ }
+
+ msg_rx_ring.virt_buffer[msg_rx_ring.rx_slot] = buf;
+ if (++msg_rx_ring.rx_slot == msg_rx_ring.size)
+ msg_rx_ring.rx_slot = 0;
+
+ out:
+ return rc;
+}
+
+EXPORT_SYMBOL(rio_hw_add_inb_buffer);
+
+/**
+ * rio_hw_get_inb_message - Fetch inbound message from the MPC85xx message unit
+ * @mport: Master port implementing the inbound message unit
+ * @mbox: Inbound mailbox number
+ *
+ * Gets the next available inbound message from the inbound message queue.
+ * A pointer to the message is returned on success or NULL on failure.
+ */
+void *rio_hw_get_inb_message(struct rio_mport *mport, int mbox)
+{
+ u32 imr;
+ u32 phys_buf, virt_buf;
+ void *buf = NULL;
+ int buf_idx;
+
+ phys_buf = in_be32((void *)&msg_regs->ifqdpar);
+
+ /* If no more messages, then bail out */
+ if (phys_buf == in_be32((void *)&msg_regs->ifqepar))
+ goto out2;
+
+ virt_buf = (u32) msg_rx_ring.virt + (phys_buf - msg_rx_ring.phys);
+ buf_idx = (phys_buf - msg_rx_ring.phys) / RIO_MAX_MSG_SIZE;
+ buf = msg_rx_ring.virt_buffer[buf_idx];
+
+ if (!buf) {
+ pr_debug(KERN_ERR
+ "RIO: inbound message copy failed, no buffers\n");
+ goto out1;
+ }
+
+ /* Copy max message size, caller is expected to allocate that big */
+ memcpy(buf, (void *)virt_buf, RIO_MAX_MSG_SIZE);
+
+ /* Clear the available buffer */
+ msg_rx_ring.virt_buffer[buf_idx] = NULL;
+
+ out1:
+ imr = in_be32((void *)&msg_regs->imr);
+ out_be32((void *)&msg_regs->imr, imr | RIO_MSG_IMR_MI);
+
+ out2:
+ return buf;
+}
+
+EXPORT_SYMBOL(rio_hw_get_inb_message);
+
+/**
+ * mpc85xx_rio_dbell_handler - MPC85xx doorbell interrupt handler
+ * @irq: Linux interrupt number
+ * @dev_instance: Pointer to interrupt-specific data
+ * @regs: Register context
+ *
+ * Handles doorbell interrupts. Parses a list of registered
+ * doorbell event handlers and executes a matching event handler.
+ */
+static irqreturn_t
+mpc85xx_rio_dbell_handler(int irq, void *dev_instance, struct pt_regs *regs)
+{
+ int dsr;
+ struct rio_mport *port = (struct rio_mport *)dev_instance;
+
+ dsr = in_be32((void *)&msg_regs->dsr);
+
+ if (dsr & DOORBELL_DSR_TE) {
+ printk(KERN_INFO "RIO: doorbell reception error\n");
+ out_be32((void *)&msg_regs->dsr, DOORBELL_DSR_TE);
+ goto out;
+ }
+
+ if (dsr & DOORBELL_DSR_QFI) {
+ printk(KERN_INFO "RIO: doorbell queue full\n");
+ out_be32((void *)&msg_regs->dsr, DOORBELL_DSR_QFI);
+ goto out;
+ }
+
+ /* XXX Need to check/dispatch until queue empty */
+ if (dsr & DOORBELL_DSR_DIQI) {
+ u32 dmsg =
+ (u32) dbell_ring.virt +
+ (in_be32((void *)&msg_regs->dqdpar) & 0xfff);
+ u32 dmr;
+ struct rio_dbell *dbell;
+ int found = 0;
+
+ pr_debug(KERN_INFO
+ "RIO: processing doorbell, sid %2.2x tid %2.2x info %4.4x\n",
+ DBELL_SID(dmsg), DBELL_TID(dmsg), DBELL_INF(dmsg));
+
+ list_for_each_entry(dbell, &port->dbells, node) {
+ if ((dbell->res->start <= DBELL_INF(dmsg)) &&
+ (dbell->res->end >= DBELL_INF(dmsg))) {
+ found = 1;
+ break;
+ }
+ }
+ if (found) {
+ dbell->dinb(port, DBELL_SID(dmsg), DBELL_TID(dmsg),
+ DBELL_INF(dmsg));
+ } else {
+ pr_debug(KERN_INFO
+ "RIO: spurious doorbell, sid %2.2x tid %2.2x info %4.4x\n",
+ DBELL_SID(dmsg), DBELL_TID(dmsg),
+ DBELL_INF(dmsg));
+ }
+ dmr = in_be32((void *)&msg_regs->dmr);
+ out_be32((void *)&msg_regs->dmr, dmr | DOORBELL_DMR_DI);
+ out_be32((void *)&msg_regs->dsr, DOORBELL_DSR_DIQI);
+ }
+
+ out:
+ return IRQ_HANDLED;
+}
+
+/**
+ * mpc85xx_rio_doorbell_init - MPC85xx doorbell interface init
+ * @mport: Master port implementing the inbound doorbell unit
+ *
+ * Initializes doorbell unit hardware and inbound DMA buffer
+ * ring. Called from mpc85xx_rio_setup().
+ */
+static void mpc85xx_rio_doorbell_init(struct rio_mport *mport)
+{
+ /* Map outbound doorbell window immediately after maintenance window */
+ dbell_win =
+ (u32) ioremap(mport->iores.start + RIO_MAINT_WIN_SIZE,
+ RIO_DBELL_WIN_SIZE);
+
+ /* Initialize inbound doorbells */
+ dbell_ring.virt = dma_alloc_coherent(NULL,
+ 512 * DOORBELL_MESSAGE_SIZE,
+ &dbell_ring.phys, GFP_KERNEL);
+
+ /* Point dequeue/enqueue pointers at first entry in ring */
+ out_be32((void *)&msg_regs->dqdpar, (u32) dbell_ring.phys);
+ out_be32((void *)&msg_regs->dqepar, (u32) dbell_ring.phys);
+
+ /* Clear interrupt status */
+ out_be32((void *)&msg_regs->dsr, 0x00000091);
+
+ /* Hook up doorbell handler */
+ request_irq(MPC85xx_IRQ_RIO_BELL, mpc85xx_rio_dbell_handler, 0,
+ "dbell_rx", (void *)mport);
+
+ /* Configure doorbells for snooping, 512 entries, and enable */
+ out_be32((void *)&msg_regs->dmr, 0x00108161);
+}
+
+static char *cmdline = NULL;
+
+static int mpc85xx_rio_get_hdid(int index)
+{
+ /* XXX Need to parse multiple entries in some format */
+ if (!cmdline)
+ return -1;
+
+ return simple_strtol(cmdline, NULL, 0);
+}
+
+static int mpc85xx_rio_get_cmdline(char *s)
+{
+ if (!s)
+ return 0;
+
+ cmdline = s;
+ return 1;
+}
+
+__setup("riohdid=", mpc85xx_rio_get_cmdline);
+
+/**
+ * mpc85xx_rio_setup - Setup MPC85xx RapidIO interface
+ * @law_start: Starting physical address of RapidIO LAW
+ * @law_size: Size of RapidIO LAW
+ *
+ * Initializes MPC85xx RapidIO hardware interface, configures
+ * master port with system-specific info, and registers the
+ * master port with the RapidIO subsystem.
+ */
+void mpc85xx_rio_setup(int law_start, int law_size)
+{
+ struct rio_ops *ops;
+ struct rio_mport *port;
+
+ ops = kmalloc(sizeof(struct rio_ops), GFP_KERNEL);
+ ops->lcread = mpc85xx_local_config_read;
+ ops->lcwrite = mpc85xx_local_config_write;
+ ops->cread = mpc85xx_rio_config_read;
+ ops->cwrite = mpc85xx_rio_config_write;
+ ops->dsend = mpc85xx_rio_doorbell_send;
+
+ port = kmalloc(sizeof(struct rio_mport), GFP_KERNEL);
+ port->id = 0;
+ port->index = 0;
+ INIT_LIST_HEAD(&port->dbells);
+ port->iores.start = law_start;
+ port->iores.end = law_start + law_size;
+ port->iores.flags = IORESOURCE_MEM;
+
+ rio_init_dbell_res(&port->riores[RIO_DOORBELL_RESOURCE], 0, 0xffff);
+ rio_init_mbox_res(&port->riores[RIO_INB_MBOX_RESOURCE], 0, 0);
+ rio_init_mbox_res(&port->riores[RIO_OUTB_MBOX_RESOURCE], 0, 0);
+ strcpy(port->name, "RIO0 mport");
+
+ port->ops = ops;
+ port->host_deviceid = mpc85xx_rio_get_hdid(port->id);
+
+ rio_register_mport(port);
+
+ regs_win = (u32) ioremap(RIO_REGS_BASE, 0x20000);
+ atmu_regs = (struct rio_atmu_regs *)(regs_win + RIO_ATMU_REGS_OFFSET);
+ maint_atmu_regs = atmu_regs + 1;
+ dbell_atmu_regs = atmu_regs + 2;
+ msg_regs = (struct rio_msg_regs *)(regs_win + RIO_MSG_REGS_OFFSET);
+
+ /* Configure maintenance transaction window */
+ out_be32((void *)&maint_atmu_regs->rowbar, 0x000c0000);
+ out_be32((void *)&maint_atmu_regs->rowar, 0x80077015);
+
+ maint_win = (u32) ioremap(law_start, RIO_MAINT_WIN_SIZE);
+
+ /* Configure outbound doorbell window */
+ out_be32((void *)&dbell_atmu_regs->rowbar, 0x000c0400);
+ out_be32((void *)&dbell_atmu_regs->rowar, 0x8004200b);
+ mpc85xx_rio_doorbell_init(port);
+}
Index: arch/ppc/syslib/ppc85xx_rio.h
===================================================================
--- /dev/null (tree:750e10a6553cacbd2b92b52fe40afdc8062f4f78)
+++ f0bf7810dbe8c4073832d6c3785364084e9523a7/arch/ppc/syslib/ppc85xx_rio.h (mode:100644)
@@ -0,0 +1,21 @@
+/*
+ * MPC85xx RapidIO definitions
+ *
+ * Copyright 2005 MontaVista Software, Inc.
+ * Matt Porter <mporter@kernel.crashing.org>
+ *
+ * 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.
+ */
+
+#ifndef __PPC_SYSLIB_PPC85XX_RIO_H
+#define __PPC_SYSLIB_PPC85XX_RIO_H
+
+#include <linux/config.h>
+#include <linux/init.h>
+
+extern void mpc85xx_rio_setup(int law_start, int law_size);
+
+#endif /* __PPC_SYSLIB_PPC85XX_RIO_H */
Index: include/asm-ppc/rio.h
===================================================================
--- /dev/null (tree:750e10a6553cacbd2b92b52fe40afdc8062f4f78)
+++ f0bf7810dbe8c4073832d6c3785364084e9523a7/include/asm-ppc/rio.h (mode:100644)
@@ -0,0 +1,18 @@
+/*
+ * RapidIO architecture support
+ *
+ * Copyright 2005 MontaVista Software, Inc.
+ * Matt Porter <mporter@kernel.crashing.org>
+ *
+ * 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.
+ */
+
+#ifndef ASM_PPC_RIO_H
+#define ASM_PPC_RIO_H
+
+extern void platform_rio_init(void);
+
+#endif /* ASM_PPC_RIO_H */
^ permalink raw reply
* Re: bd_t Cleaning: Board Changes
From: Mark A. Greer @ 2005-06-01 18:10 UTC (permalink / raw)
To: Jon Loeliger; +Cc: linuxppc-embedded@ozlabs.org
In-Reply-To: <1117221410.26114.95.camel@cashmere.sps.mot.com>
Jon Loeliger wrote:
> <snip>
>
>Part Two of Four, the Board Changes.
>
> ppc/platforms/4xx/ash.h | 21 -
> ppc/platforms/4xx/bubinga.c | 4
> ppc/platforms/4xx/bubinga.h | 23 -
> ppc/platforms/4xx/cpci405.h | 2
> ppc/platforms/4xx/ebony.c | 9
> ppc/platforms/4xx/ep405.c | 12
> ppc/platforms/4xx/ep405.h | 13
> ppc/platforms/4xx/luan.c | 7
> ppc/platforms/4xx/oak.c | 15
> ppc/platforms/4xx/oak.h | 19 -
> ppc/platforms/4xx/oak_setup.h | 2
> ppc/platforms/4xx/ocotea.c | 13
> ppc/platforms/4xx/redwood5.h | 13
> ppc/platforms/4xx/redwood6.c | 27 -
> ppc/platforms/4xx/redwood6.h | 13
> ppc/platforms/4xx/sycamore.h | 22 -
> ppc/platforms/4xx/walnut.h | 22 -
> ppc/platforms/4xx/xilinx_ml300.h | 12
> ppc/platforms/83xx/mpc834x_sys.c | 49 +-
> ppc/platforms/83xx/mpc834x_sys.h | 1
> ppc/platforms/85xx/mpc8540_ads.c | 57 ++-
> ppc/platforms/85xx/mpc8560_ads.c | 21 -
> ppc/platforms/85xx/mpc85xx_ads_common.c | 10
> ppc/platforms/85xx/mpc85xx_ads_common.h | 1
> ppc/platforms/85xx/mpc85xx_cds_common.c | 48 +-
> ppc/platforms/85xx/mpc85xx_cds_common.h | 1
> ppc/platforms/85xx/sbc8560.c | 19 -
> ppc/platforms/85xx/sbc85xx.c | 14
> ppc/platforms/85xx/sbc85xx.h | 1
> ppc/platforms/85xx/stx_gp3.c | 34 -
> ppc/platforms/85xx/stx_gp3.h | 1
> ppc/platforms/bseip.h | 13
> ppc/platforms/ccm.h | 2
> ppc/platforms/cpci690.h | 10
> ppc/platforms/est8260.h | 18
> ppc/platforms/fads.h | 2
> ppc/platforms/hdpu.c | 13
> ppc/platforms/hermes.h | 2
> ppc/platforms/ip860.h | 2
> ppc/platforms/ivms8.h | 2
> ppc/platforms/katana.c | 6
> ppc/platforms/lantec.h | 2
> ppc/platforms/lite5200.c | 9
> ppc/platforms/lwmon.h | 2
> ppc/platforms/mbx.h | 22 -
> ppc/platforms/pcu_e.h | 2
> ppc/platforms/pq2ads.c | 1
> ppc/platforms/pq2ads.h | 2
> ppc/platforms/radstone_ppc7d.c | 32 -
> ppc/platforms/radstone_ppc7d.h | 2
> ppc/platforms/rpx8260.h | 19 -
> ppc/platforms/rpxclassic.h | 13
> ppc/platforms/rpxlite.h | 13
> ppc/platforms/sandpoint.c | 11
> ppc/platforms/sandpoint.h | 2
> ppc/platforms/sbc82xx.c | 6
> ppc/platforms/sbc82xx.h | 2
> ppc/platforms/sbs8260.h | 18
> ppc/platforms/spd8xx.h | 2
> ppc/platforms/tqm8260.h | 2
> ppc/platforms/tqm8260_setup.c | 1
> ppc/platforms/tqm8xx.h | 2
>
>
>
<snip>
All,
So is this patch going to go in? I haven't seen anyone "push it up".
The reason I'm asking is that I have a couple patches that I would like
to push up but they will collide with this one so I need to know if it
(or a variation thereof) is going to go in or not.
Thanks,
Mark
^ permalink raw reply
* [PATCH][1/3] RapidIO support: core
From: Matt Porter @ 2005-06-01 18:08 UTC (permalink / raw)
To: torvalds, akpm; +Cc: linux-kernel, linuxppc-embedded
Adds a RapidIO subsystem to the kernel. RIO is a switched
fabric interconnect used in higher-end embedded applications.
The curious can look at the specs over at http://www.rapidio.org
The core code implements enumeration/discovery, management of
devices/resources, and interfaces for RIO drivers.
There's a lot more to do to take advantages of all the hardware
features. However, this should provide a good base for folks
with RIO hardware to start contributing.
Signed-off-by: Matt Porter <mporter@kernel.crashing.org>
Patch is 108KB and can be found here:
ftp://source.mvista.com/pub/rio/l26_rio_core.patch
-Matt
^ permalink raw reply
* [PATCH] cpm_uart: Route SCC2 pins for the STx GP3 board
From: Matt Porter @ 2005-06-01 17:51 UTC (permalink / raw)
To: akpm, kumar.gala; +Cc: linux-kernel, linuxppc-embedded
Adds SCC2 pin routing specific to the GP3 board.
Signed-off-by: Matt Porter <mporter@kernel.crashing.org>
Signed-off-by: Kumar Gala <kumar.gala@freescale.com>
Index: drivers/serial/cpm_uart/cpm_uart_cpm2.c
===================================================================
--- b4bedd69e60ae8cc7d89f3c97c617a444eb43292/drivers/serial/cpm_uart/cpm_uart_cpm2.c (mode:100644)
+++ uncommitted/drivers/serial/cpm_uart/cpm_uart_cpm2.c (mode:100644)
@@ -134,12 +134,21 @@
void scc2_lineif(struct uart_cpm_port *pinfo)
{
+ /*
+ * STx GP3 uses the SCC2 secondary option pin assignment
+ * which this driver doesn't account for in the static
+ * pin assignments. This kind of board specific info
+ * really has to get out of the driver so boards can
+ * be supported in a sane fashion.
+ */
+#ifndef CONFIG_STX_GP3
volatile iop_cpm2_t *io = &cpm2_immr->im_ioport;
io->iop_pparb |= 0x008b0000;
io->iop_pdirb |= 0x00880000;
io->iop_psorb |= 0x00880000;
io->iop_pdirb &= ~0x00030000;
io->iop_psorb &= ~0x00030000;
+#endif
cpm2_immr->im_cpmux.cmx_scr &= 0xff00ffff;
cpm2_immr->im_cpmux.cmx_scr |= 0x00090000;
pinfo->brg = 2;
^ permalink raw reply
* [PATCH] ppc32: Removed dependency on CONFIG_CPM2 for building mpc85xx_device.c
From: Kumar Gala @ 2005-06-01 17:36 UTC (permalink / raw)
To: Andrew Morton; +Cc: linux-kernel, linuxppc-embedded
Previously we needed CONFIG_CPM2 enabled to get the proper IRQ
ifdef's for CPM interrupts. Recent changes have caused that to
be no longer necessary.
Signed-off-by: Kumar Gala <kumar.gala@freescale.com>
---
commit 22774efc1bef9f9a0fd9b34d44bf10da787e3d91
tree 115c991f9030418e78a7aa0f23d678d0141e0746
parent 6e7c21f278abb17a9bbdc6fd1f1b1b96e6677fdb
author Kumar K. Gala <kumar.gala@freescale.com> Wed, 01 Jun 2005 12:34:30 -0500
committer Kumar K. Gala <kumar.gala@freescale.com> Wed, 01 Jun 2005 12:34:30 -0500
arch/ppc/syslib/mpc85xx_devices.c | 2 --
1 files changed, 0 insertions(+), 2 deletions(-)
diff --git a/arch/ppc/syslib/mpc85xx_devices.c b/arch/ppc/syslib/mpc85xx_devices.c
--- a/arch/ppc/syslib/mpc85xx_devices.c
+++ b/arch/ppc/syslib/mpc85xx_devices.c
@@ -321,7 +321,6 @@ struct platform_device ppc_sys_platform_
},
},
},
-#ifdef CONFIG_CPM2
[MPC85xx_CPM_FCC1] = {
.name = "fsl-cpm-fcc",
.id = 1,
@@ -575,7 +574,6 @@ struct platform_device ppc_sys_platform_
},
},
},
-#endif /* CONFIG_CPM2 */
[MPC85xx_eTSEC1] = {
.name = "fsl-gianfar",
.id = 1,
^ permalink raw reply
* Tiny patch for arch/ppc/kernel/cputable.c to properly support the IBM PowerPC 750CXe rev 3.1
From: Nicolas DET @ 2005-06-01 18:14 UTC (permalink / raw)
To: linuxppc-dev
[-- Attachment #1: Type: text/plain, Size: 307 bytes --]
Amiga............: SimpleMail http://simplemail.sourceforge.net/
Unix.............: Metamail ftp://ftp.bellcore.com/nsb/
Windows/Macintosh: Eudora http://www.qualcomm.com/
General info about MIME can be found at:
http://www.cis.ohio-state.edu/hypertext/faq/usenet/mail/mime-faq/top.html
[-- Attachment #2: Type: text/plain, Size: 425 bytes --]
Hello,
You can find enclosed a small patch to properly support the 750 CXe rev
3.1. Indeed, the current kernel (2.6.11.11) only supports rev 2.1 and
ignores 3.1
It's a tiny patch: it only add an entry in the table with the correct PVR
and name. Others values has been copied from 750CXe rev 2.1.
I succesfully patched & compiled a vanila 2.6.11.11 from kernel.org.
Your sincerly,
--
Nicolas DET
MorphOS & Linux developer
[-- Attachment #3: patch_750CXe_2.6.11 --]
[-- Type: application/octet-stream, Size: 1854 bytes --]
--- linux-2.6.11.orig/arch/ppc/kernel/cputable.c 2005-03-02 08:38:09.000000000 +0100
+++ linux-2.6.11_nico/arch/ppc/kernel/cputable.c 2005-03-04 15:39:11.032975088 +0100
@@ -198,20 +198,6 @@
.num_pmcs = 4,
.cpu_setup = __setup_cpu_750
},
- { /* 745/755 */
- .pvr_mask = 0xfffff000,
- .pvr_value = 0x00083000,
- .cpu_name = "745/755",
- .cpu_features = CPU_FTR_COMMON |
- CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_MAYBE_CAN_DOZE |
- CPU_FTR_USE_TB | CPU_FTR_L2CR | CPU_FTR_TAU |
- CPU_FTR_HPTE_TABLE | CPU_FTR_MAYBE_CAN_NAP,
- .cpu_user_features = COMMON_PPC,
- .icache_bsize = 32,
- .dcache_bsize = 32,
- .num_pmcs = 4,
- .cpu_setup = __setup_cpu_750
- },
{ /* 750CX (80100 and 8010x?) */
.pvr_mask = 0xfffffff0,
.pvr_value = 0x00080100,
@@ -254,6 +240,34 @@
.num_pmcs = 4,
.cpu_setup = __setup_cpu_750cx
},
+ { /* 750CXe (00082311 or 00083311) revision 3.1 / 3.1 pre_GA */
+ .pvr_mask = 0xffff0fff,
+ .pvr_value = 0x00080311,
+ .cpu_name = "750CXe rev 3.1",
+ .cpu_features = CPU_FTR_COMMON |
+ CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_MAYBE_CAN_DOZE |
+ CPU_FTR_USE_TB | CPU_FTR_L2CR | CPU_FTR_TAU |
+ CPU_FTR_HPTE_TABLE | CPU_FTR_MAYBE_CAN_NAP,
+ .cpu_user_features = COMMON_PPC,
+ .icache_bsize = 32,
+ .dcache_bsize = 32,
+ .num_pmcs = 4,
+ .cpu_setup = __setup_cpu_750cx
+ },
+ { /* 745/755 */
+ .pvr_mask = 0xfffff000,
+ .pvr_value = 0x00083000,
+ .cpu_name = "745/755",
+ .cpu_features = CPU_FTR_COMMON |
+ CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_MAYBE_CAN_DOZE |
+ CPU_FTR_USE_TB | CPU_FTR_L2CR | CPU_FTR_TAU |
+ CPU_FTR_HPTE_TABLE | CPU_FTR_MAYBE_CAN_NAP,
+ .cpu_user_features = COMMON_PPC,
+ .icache_bsize = 32,
+ .dcache_bsize = 32,
+ .num_pmcs = 4,
+ .cpu_setup = __setup_cpu_750
+ },
{ /* 750FX rev 1.x */
.pvr_mask = 0xffffff00,
.pvr_value = 0x70000100,
^ permalink raw reply
* Re: Booting the linux-ppc64 kernel & flattened device tree v0.4
From: Jon Loeliger @ 2005-06-01 16:58 UTC (permalink / raw)
To: Benjamin Herrenschmidt; +Cc: linuxppc-embedded@ozlabs.org
In-Reply-To: <1117614390.19020.24.camel@gaston>
On Wed, 2005-06-01 at 03:26, Benjamin Herrenschmidt wrote:
> Here's the fourth version of my document along with new kernel patches
> for the new improved flattened format, and the first release of the
> device-tree "compiler" tool. The patches will be posted as a reply to
> this email. The compiler, dtc, can be downloaded, the URL is in the
> document.
Ben,
Does it make sense to do this as well?
Thanks,
jdl
diff -Nur dtc.orig/lsprop.c dtc/lsprop.c
--- dtc.orig/lsprop.c 1969-12-31 18:00:00.000000000 -0600
+++ dtc/lsprop.c 2005-06-01 11:43:01.000002000 -0500
@@ -0,0 +1,221 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <dirent.h>
+
+int recurse;
+int maxbytes = 128;
+int words_per_line = 0;
+char *buf;
+
+void lsprop(FILE *f, char *name);
+void lsdir(char *name);
+
+main(int ac, char **av)
+{
+ FILE *f;
+ int i;
+ struct stat sb;
+ char *endp;
+
+ while ((i = getopt(ac, av, "Rm:w:")) != EOF) {
+ switch (i) {
+ case 'R':
+ recurse = 1;
+ break;
+ case 'm':
+ maxbytes = strtol(optarg, &endp, 0);
+ if (endp == optarg) {
+ fprintf(stderr, "%s: bad argument (%s) to -m option\n", av[0],
+ optarg);
+ exit(1);
+ }
+ maxbytes = (maxbytes + 15) & -16;
+ break;
+ case 'w':
+ words_per_line = strtol(optarg, &endp, 0);
+ if (endp == optarg) {
+ fprintf(stderr, "%s: bad argument (%s) to -w option\n",
+ av[0], optarg);
+ exit(1);
+ }
+ break;
+ }
+ }
+
+ buf = malloc(maxbytes);
+ if (buf == 0) {
+ fprintf(stderr, "%s: virtual memory exhausted\n", av[0]);
+ exit(1);
+ }
+
+ if (optind == ac)
+ lsdir(".");
+ else
+ for (i = optind; i < ac; ++i) {
+ if (stat(av[i], &sb) < 0) {
+ perror(av[i]);
+ continue;
+ }
+ if (S_ISREG(sb.st_mode)) {
+ f = fopen(av[i], "r");
+ if (f == NULL) {
+ perror(av[i]);
+ continue;
+ }
+ lsprop(f, av[i]);
+ fclose(f);
+ } else if (S_ISDIR(sb.st_mode)) {
+ lsdir(av[i]);
+ }
+ }
+ exit(0);
+}
+
+void lsdir(char *name)
+{
+ DIR *d;
+ struct dirent *de;
+ char *p, *q;
+ struct stat sb;
+ FILE *f;
+ int np = 0;
+
+ d = opendir(name);
+ if (d == NULL) {
+ perror(name);
+ return;
+ }
+
+ p = malloc(strlen(name) + 520);
+ if (p == 0) {
+ fprintf(stderr, "%s: virtual memory exhausted\n", name);
+ closedir(d);
+ return;
+ }
+ strcpy(p, name);
+ q = p + strlen(p);
+ while (q > p && q[-1] == '/')
+ --q;
+ if (q == p + 1 && p[0] == '.')
+ q = p;
+ else
+ *q++ = '/';
+
+ while ((de = readdir(d)) != NULL) {
+ if (strcmp(de->d_name, ".") == 0 || strcmp(de->d_name, "..") == 0)
+ continue;
+ strcpy(q, de->d_name);
+ if (stat(p, &sb) < 0) {
+ perror(p);
+ continue;
+ }
+ if (S_ISREG(sb.st_mode)) {
+ f = fopen(p, "r");
+ if (f == NULL) {
+ perror(p);
+ } else {
+ lsprop(f, de->d_name);
+ fclose(f);
+ ++np;
+ }
+ }
+ }
+ rewinddir(d);
+ while ((de = readdir(d)) != NULL) {
+ if (strcmp(de->d_name, ".") == 0 || strcmp(de->d_name, "..") == 0)
+ continue;
+ strcpy(q, de->d_name);
+ if (lstat(p, &sb) < 0) {
+ perror(p);
+ continue;
+ }
+ if (S_ISDIR(sb.st_mode)) {
+ if (np)
+ printf("\n");
+ printf("%s:\n", p);
+ lsdir(p);
+ ++np;
+ }
+ }
+ free(p);
+ closedir(d);
+}
+
+void lsprop(FILE *f, char *name)
+{
+ int n, nw, npl, i, j;
+
+ n = fread(buf, 1, maxbytes, f);
+ if (n < 0) {
+ printf("%s: read error\n", name);
+ return;
+ }
+ printf("%-16s", name);
+ if (strlen(name) > 16)
+ printf("\n\t\t");
+ for (i = 0; i < n; ++i)
+ if (buf[i] >= 0x7f ||
+ (buf[i] < 0x20 && buf[i] != '\r' && buf[i] != '\n'
+ && buf[i] != '\t' && buf[i] != 0))
+ break;
+ if (i == n && n != 0 && (n == 1 || buf[0] != 0) && buf[n-1] == 0) {
+ printf(" \"");
+ for (i = 0; i < n - 1; ++i)
+ if (buf[i] == 0)
+ printf("\"\n\t\t \"");
+ else if (buf[i] == '\r' || buf[i] == '\n')
+ printf("\n\t\t ");
+ else
+ putchar(buf[i]);
+ putchar('"');
+ } else if ((n & 3) == 0) {
+ nw = n >> 2;
+ if (nw == 1) {
+ i = *(int *)buf;
+ printf(" %.8x", i);
+ if (i > -0x10000 && !(i >= 0 && i <= 9))
+ printf(" (%d)", i);
+ } else {
+ npl = words_per_line;
+ if (npl <= 0) {
+ if ((nw % 6) == 0)
+ npl = 6;
+ else if ((nw % 5) == 0)
+ npl = 5;
+ else
+ npl = 4;
+ }
+ for (i = 0; i < nw; i += npl) {
+ if (i != 0)
+ printf("\n\t\t");
+ for (j = 0; j < npl && i + j < nw; ++j)
+ printf(" %.8x", ((unsigned int *)buf)[i+j]);
+ }
+ }
+ } else {
+ for (i = 0; i < n; i += 16) {
+ if (i != 0)
+ printf("\n\t\t");
+ for (j = 0; j < 16 && i + j < n; ++j)
+ printf(" %.2x", buf[i+j]);
+ for (; j < 16; ++j)
+ printf(" ");
+ for (j = 0; j < 16 && i + j < n; ++j)
+ if (buf[i+j] > 0x20 && buf[i+j] <= 0x7e)
+ putchar(buf[i+j]);
+ else
+ putchar('.');
+ }
+ }
+ printf("\n");
+ if (n == maxbytes) {
+ while ((i = fread(buf, 1, maxbytes, f)) > 0)
+ n += i;
+ if (n > maxbytes)
+ printf("\t\t [%d bytes total]\n", n);
+ }
+}
+
diff -Nur dtc.orig/Makefile dtc/Makefile
--- dtc.orig/Makefile 2005-06-01 11:44:29.000002000 -0500
+++ dtc/Makefile 2005-06-01 11:46:26.000002000 -0500
@@ -1,15 +1,21 @@
-TARGETS = dtc
+TARGETS = dtc lsprop
CFLAGS = -Wall -g
-OBJS = dtc.o livetree.o flattree.o data.o treesource.o fstree.o \
+OBJS-dtc = dtc.o livetree.o flattree.o data.o treesource.o fstree.o \
y.tab.o lex.yy.o
+OBJS-lsprop = lsprop.o
+
+
default: $(TARGETS)
-dtc: $(OBJS)
+dtc: $(OBJS-dtc)
+ $(LINK.c) -o $@ $^
+
+lsprop: $(OBJS-lsprop)
$(LINK.c) -o $@ $^
-$(OBJS): dtc.h
+$(OBJS-dtc): dtc.h
y.tab.c y.tab.h: dtc-parser.y
$(YACC) -d $<
^ permalink raw reply
* linux2.4.24 on Memec EVB no output on console
From: andreas_schmidt @ 2005-06-01 15:34 UTC (permalink / raw)
To: linuxppc-embedded
Hi at all
I have already postet this problem there but i want make some adds there.
Configs:
I use Memec EVB with Virtex2Pro
u-boot 1.1.2
linux2.4.24 with modify ml300 config
I ported u-boot on this board and can download the uImage from the ethernet.
Problem:
Atfer uncompressing the kernel I get no output on console
=> bootm
## Booting image at 00400000 ...
Image Name: Linux-2.4.24-pre2
Image Type: PowerPC Linux Kernel Image (gzip compressed)
Data Size: 720036 Bytes = 703.2 kB
Load Address: 00000000
Entry Point: 00000000
Verifying Checksum ... OK
Uncompressing Kernel Image ... OK
I have oportunity to debug the kernel and I can see that the kernel runs!
It write something in buffer and init the serial driver. But somewhere it get illegal
kernel access and thhe kernel call exeption handler. On which point the problem is I
can't say because I can't find the start address from kernel, to set a breakpoint there
and debug. I can only stop the processor and then debug.
Perhaps had someone the same problems and can help me.
Many thangs for any help!
best regards,
Andreas
^ permalink raw reply
* Re: copy_from_user( ) problem...help
From: Hollis Blanchard @ 2005-06-01 15:31 UTC (permalink / raw)
To: Garcia Jérémie; +Cc: linuxppc-dev
In-Reply-To: <D4FDDD1349B5AC46B68FC26AD8AF42D6226B2D@exnet.3il.fr>
On Jun 1, 2005, at 9:00 AM, Garcia J=E9r=E9mie wrote:
> Hi everybody,
> I'm tryin to write some device drivers modules in order to manage some=20=
> of our devices of our ppc405EP based board.
> I read the Allessandro Rubini book (Linux Kernel device drivers) in=20
> order to help me.
> Before going on difficult stuff, I'd like to make some basic training=20=
> and experiments.
> What I want to do seems to be very easy (but...):
> - a user space programm has a global structure and contains an=20
> integer and a char
> - the user space programm loads the module with a parameter: the=20
> structure address
> - during the init_module(),I check that the address can be accessed=20=
> in R/W mode with the access_ok()
> - the module copies the user structure in its own context and prints=20=
> the values retreived
When you do your copy_from_user, what guarantee do you have that the=20
user process is your test application? If anything, I would expect it=20
to be insmod (you can printk current->comm to see). Instead you could=20
implement a write method and create a device node for the user app to=20
open and write to.
However, for this specific example that's not in good style. If all you=20=
really want to do is communicate settings to a kernel module, have a=20
look at sysfs.
-Hollis=
^ permalink raw reply
* copy_from_user( ) problem...help
From: Garcia Jérémie @ 2005-06-01 14:00 UTC (permalink / raw)
To: linuxppc-dev
Hi everybody,
I'm tryin to write some device drivers modules in order to manage some =
of our devices of our ppc405EP based board.
I read the Allessandro Rubini book (Linux Kernel device drivers) in =
order to help me.
Before going on difficult stuff, I'd like to make some basic training =
and experiments.
What I want to do seems to be very easy (but...):
- a user space programm has a global structure and contains an integer =
and a char
- the user space programm loads the module with a parameter: the =
structure address
- during the init_module(),I check that the address can be accessed in =
R/W mode with the access_ok()
- the module copies the user structure in its own context and prints =
the values retreived
So, it's supposed to be a very easy operation, but something goes wrong. =
Could someone give me a clue cause
I read it again and again and I don't get what's the matter. Here is the =
code:
/************************************************************************=
******/
/* USER SPACE PROG =
*/
/************************************************************************=
******/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
=20
typedef struct une_structure
{
int un_entier;
char un_char;
}UNE_STRUCTURE;
UNE_STRUCTURE my_structure;
void main(void)
{
char buff[100];
/* Init of the structure */
my_structure.un_entier =3D 5;
my_structure.un_char =3D 'a';
=20
/* Build the shell command to load the module */
sprintf(buff,"insmod -q ./un_module.o addr=3D%p",&my_structure);
/* Print the shell command that loads the module */
printf("\nCommmande : ");
puts(buff);
=20
/* Load the module*/
system(buff);
sleep(2);
/* Remove the module */
system("rmmod un_module"); =20
}
/************************************************************************=
/
/* KERNEL MODULE =
*/
/************************************************************************=
/
[...]
typedef struct une_structure
{
int un_entier;
char un_char;
}UNE_STRUCTURE;
UNE_STRUCTURE *addr =3D 0x0; /* default value */
MODULE_PARM(addr,"l"); /* get the address of the user space =
structure=20
given in argument at insmod() =
*/
int init_module(void)
{
int rc;
UNE_STRUCTURE * my_structure;
=20
printk("Address of the user structure : %d\n",(int)addr);
/* Alloc space for ou structure */
my_structure =3D kmalloc(sizeof(UNE_STRUCTURE),GFP_DMA);
if(my_structure=3D=3DNULL)
{
printk("Kernel memory allocation failed!\n");
return -1;
}
else
printk("Kernel memory allocation succeeded!\n");
rc =3D access_ok(VERIFY_READ,(void *)addr,sizeof(UNE_STRUCTURE));
if(rc !=3D 0)
{ =20
rc =3D access_ok(VERIFY_WRITE,(void *)addr,sizeof(UNE_STRUCTURE));
if(rc !=3D 0)
{
rc =3D copy_from_user(my_structure,(void =
*)addr,sizeof(UNE_STRUCTURE));
if(rc)
printk("Error in copy_from_user, rc=3D%d\n",rc);
else
{ =20
printk("Values of the retreived user-space structure 's =
fields:\n");
printk("\t -> un_entier =3D %d \n",my_structure->un_entier);
printk("\t -> un_unsigned_char =3D %c =
\n",my_structure->un_char);
}
=20
}
else
{
printk("Erreur in accessing addr in WRITE mode\n");
return -1;
}=20
}
else
{
printk("Erreur in accessing addr in READ mode\n");
return -1;
}
return 0;
}
/************************************************************************=
***/
/* EXECUTION RESULTS =
*/
/************************************************************************=
***/
root@10.16.9.232:/home/testDir# ./une_appli.exe
[USER-SPACE]Commmande : insmod -q ./un_module.o addr=3D0x10010a74
[KERN-SPACE]Address of the user structure : 268503668 // =
is the same if converted in hexa=20
[KERN-SPACE]Kernel memory allocation succeeded!
[KERN-SPACE]Values of the retreived user-space structure 's fields:
-> un_entier =3D -1857486844 // =
weird result and !=3D 5
-> un_unsigned_char =3D . // =
weird result and !=3D 'a'
[KERN-SPACE]Now releasing the module...
As you can see, I don't really retreived the user-space structure in the =
kernel. Is it an address problem?
If I understood well, no ioremap is needded here cause the address given =
in argument of insmod is from MMU.
So what's the problem ; I really think that I'm dealing with a wrong =
address.=20
Please help a newbie that would like to understand... Tks for your =
precious help.
Jeremie
=20
^ permalink raw reply
* How to allocate uncached memory on 82xx?
From: Alex Zeffertt @ 2005-06-01 10:53 UTC (permalink / raw)
To: linuxppc-embedded
Hi all,
Can anybody tell me how to make uncached a region of memory on the
PowerQUICCII (MPC8280). The region is allocated with
kmalloc(size,GFP_KERNEL | GFP_DMA);
TIA,
Alex
^ permalink raw reply
* Re: ML300-gpio
From: Andrei Konovalov @ 2005-06-01 10:42 UTC (permalink / raw)
To: colui77; +Cc: linuxppc-embedded
In-Reply-To: <4293EE1500015698@ims2a.cp.tin.it>
colui77@virgilio.it wrote:
> hi all,
> I'm working with the ML300 platform running the shipped Montavista Linux
> (and hw configuration). I need to use the onboard gpio and I found a driver,
> the xilinx_gpio, that I have loaded (insmod xilinx_gpio). After insmoding
> the driver it is registered in /dev/xgpio (why is not it loaded in /proc/
> before?) I have tried to use the GPIOs...
>
> cat "111111000000" > /dev/xgpio
You must use ioctl's.
This driver has the same API as IBM OCP GPIO driver.
Please check include/linux/ibm_ocp_gpio.h.
Thanks,
Andrei
> I was expecting some leds lighting but nothing at all...
> Is there someone experienced with the ml300 gpios?
> Please I need help
> Luigi
>
>
>
> _______________________________________________
> Linuxppc-embedded mailing list
> Linuxppc-embedded@ozlabs.org
> https://ozlabs.org/mailman/listinfo/linuxppc-embedded
^ permalink raw reply
* ML300-gpio
From: colui77 @ 2005-06-01 10:21 UTC (permalink / raw)
To: linuxppc-embedded
hi all,
I'm working with the ML300 platform running the shipped Montavista Linux
(and hw configuration). I need to use the onboard gpio and I found a driv=
er,
the xilinx_gpio, that I have loaded (insmod xilinx_gpio). After insmoding=
the driver it is registered in /dev/xgpio (why is not it loaded in /proc/=
before?) I have tried to use the GPIOs...
cat "111111000000" > /dev/xgpio
I was expecting some leds lighting but nothing at all...
Is there someone experienced with the ml300 gpios?
Please I need help
Luigi
^ permalink raw reply
* Re: Booting the linux-ppc64 kernel & flattened device tree v0.4
From: Benjamin Herrenschmidt @ 2005-06-01 8:28 UTC (permalink / raw)
To: u-boot-users, linuxppc-dev list, linuxppc64-dev,
linuxppc-embedded
In-Reply-To: <1117614390.19020.24.camel@gaston>
Here is the kernel patch. It applies on top of the various prom_init.c
bug fixes that I already posted today on the linuxppc-dev &
linuxppc64-dev lists (those will be in the next -mm and maybe in
2.6.12).
This patch is intended to hit upstream by 2.6.13
Index: linux-work/arch/ppc64/kernel/prom_init.c
===================================================================
--- linux-work.orig/arch/ppc64/kernel/prom_init.c 2005-06-01 16:02:28.000000000 +1000
+++ linux-work/arch/ppc64/kernel/prom_init.c 2005-06-01 16:07:21.000000000 +1000
@@ -1514,7 +1514,14 @@
return 0;
}
-static void __init scan_dt_build_strings(phandle node, unsigned long *mem_start,
+/*
+ * The Open Firmware 1275 specification states properties must be 31 bytes or
+ * less, however not all firmwares obey this. Make it 64 bytes to be safe.
+ */
+#define MAX_PROPERTY_NAME 64
+
+static void __init scan_dt_build_strings(phandle node,
+ unsigned long *mem_start,
unsigned long *mem_end)
{
unsigned long offset = reloc_offset();
@@ -1527,14 +1534,19 @@
/* get and store all property names */
prev_name = RELOC("");
for (;;) {
-
- /* 32 is max len of name including nul. */
- namep = make_room(mem_start, mem_end, 32, 1);
+ namep = make_room(mem_start, mem_end, MAX_PROPERTY_NAME, 1);
if (call_prom("nextprop", 3, 1, node, prev_name, namep) <= 0) {
/* No more nodes: unwind alloc */
*mem_start = (unsigned long)namep;
break;
}
+
+ /* skip "name" */
+ if (strcmp(namep, RELOC("name")) == 0) {
+ *mem_start = (unsigned long)namep;
+ prev_name = RELOC("name");
+ continue;
+ }
soff = dt_find_string(namep);
if (soff != 0) {
*mem_start = (unsigned long)namep;
@@ -1555,72 +1567,83 @@
}
}
-/*
- * The Open Firmware 1275 specification states properties must be 31 bytes or
- * less, however not all firmwares obey this. Make it 64 bytes to be safe.
- */
-#define MAX_PROPERTY_NAME 64
-
static void __init scan_dt_build_struct(phandle node, unsigned long *mem_start,
unsigned long *mem_end)
{
- int l, align;
phandle child;
- char *namep, *prev_name, *sstart, *p, *ep;
+ char *namep, *prev_name, *sstart, *p, *ep, *lp, *path;
unsigned long soff;
unsigned char *valp;
unsigned long offset = reloc_offset();
- char pname[MAX_PROPERTY_NAME];
- char *path;
-
- path = RELOC(prom_scratch);
+ static char pname[MAX_PROPERTY_NAME] __initdata;
+ int l;
dt_push_token(OF_DT_BEGIN_NODE, mem_start, mem_end);
- /* get the node's full name */
+ /* get the node's full name for debugging */
+ path = RELOC(prom_scratch);
+ memset(path, 0, PROM_SCRATCH_SIZE);
+ call_prom("package-to-path", 3, 1, node, path, PROM_SCRATCH_SIZE-1);
+ prom_debug(" %s\n", path);
+
+ /* get the node's full name for actual use */
namep = (char *)*mem_start;
l = call_prom("package-to-path", 3, 1, node,
namep, *mem_end - *mem_start);
if (l >= 0) {
+ int had_fixup = 0;
+
/* Didn't fit? Get more room. */
if (l+1 > *mem_end - *mem_start) {
namep = make_room(mem_start, mem_end, l+1, 1);
call_prom("package-to-path", 3, 1, node, namep, l);
}
- namep[l] = '\0';
- /* Fixup an Apple bug where they have bogus \0 chars in the
- * middle of the path in some properties
- */
- for (p = namep, ep = namep + l; p < ep; p++)
- if (*p == '\0') {
- memmove(p, p+1, ep - p);
- ep--; l--;
- }
- *mem_start = _ALIGN(((unsigned long) namep) + strlen(namep) + 1, 4);
+ ep = namep + l;
+ *ep = '\0';
+ /* now try to find the unit name in that mess */
+ for (p = namep, lp = NULL; p < ep; p++) {
+ if (*p == '/')
+ lp = p + 1;
+ /* bug fix: apple's OF has a funny bug where they have
+ * a '\0' in the name/path string of some nodes.
+ * We fix that up here
+ */
+ if (*p == '\0') {
+ memmove(p, p+1, ep - p);
+ ep--; l--;
+ had_fixup = 1;
+ }
+ }
+ if (had_fixup)
+ prom_printf("fixed up bogus name for %s\n", namep);
+ if (lp != NULL)
+ memmove(namep, lp, strlen(lp) + 1);
+ *mem_start = _ALIGN(((unsigned long) namep) +
+ strlen(namep) + 1, 4);
}
- /* get it again for debugging */
- memset(path, 0, PROM_SCRATCH_SIZE);
- call_prom("package-to-path", 3, 1, node, path, PROM_SCRATCH_SIZE-1);
-
/* get and store all properties */
prev_name = RELOC("");
sstart = (char *)RELOC(dt_string_start);
for (;;) {
- if (call_prom("nextprop", 3, 1, node, prev_name, pname) <= 0)
- break;
-
- /* find string offset */
- soff = dt_find_string(pname);
+ if (call_prom("nextprop", 3, 1, node, prev_name,
+ RELOC(pname)) <= 0)
+ break;
+ if (strcmp(RELOC(pname), RELOC("name")) == 0) {
+ prev_name = RELOC("name");
+ continue;
+ }
+ /* find string offset */
+ soff = dt_find_string(RELOC(pname));
if (soff == 0) {
- prom_printf("WARNING: Can't find string index for <%s>, node %s\n",
- pname, path);
+ prom_printf("WARNING: Can't find string index "
+ "for <%s>, node %s\n", RELOC(pname), path);
break;
}
prev_name = sstart + soff;
/* get length */
- l = call_prom("getproplen", 2, 1, node, pname);
+ l = call_prom("getproplen", 2, 1, node, RELOC(pname));
/* sanity checks */
if (l < 0)
@@ -1629,7 +1652,7 @@
prom_printf("WARNING: ignoring large property ");
/* It seems OF doesn't null-terminate the path :-( */
prom_printf("[%s] ", path);
- prom_printf("%s length 0x%x\n", pname, l);
+ prom_printf("%s length 0x%x\n", RELOC(pname), l);
continue;
}
@@ -1639,17 +1662,16 @@
dt_push_token(soff, mem_start, mem_end);
/* push property content */
- align = (l >= 8) ? 8 : 4;
- valp = make_room(mem_start, mem_end, l, align);
- call_prom("getprop", 4, 1, node, pname, valp, l);
+ valp = make_room(mem_start, mem_end, l, 4);
+ call_prom("getprop", 4, 1, node, RELOC(pname), valp, l);
*mem_start = _ALIGN(*mem_start, 4);
}
/* Add a "linux,phandle" property. */
soff = dt_find_string(RELOC("linux,phandle"));
if (soff == 0)
- prom_printf("WARNING: Can't find string index for <linux-phandle>"
- " node %s\n", path);
+ prom_printf("WARNING: Can't find string index for"
+ " <linux-phandle> node %s\n", path);
else {
dt_push_token(OF_DT_PROP, mem_start, mem_end);
dt_push_token(4, mem_start, mem_end);
@@ -1699,7 +1721,8 @@
/* Build header and make room for mem rsv map */
mem_start = _ALIGN(mem_start, 4);
- hdr = make_room(&mem_start, &mem_end, sizeof(struct boot_param_header), 4);
+ hdr = make_room(&mem_start, &mem_end,
+ sizeof(struct boot_param_header), 4);
RELOC(dt_header_start) = (unsigned long)hdr;
rsvmap = make_room(&mem_start, &mem_end, sizeof(mem_reserve_map), 8);
@@ -1712,11 +1735,11 @@
namep = make_room(&mem_start, &mem_end, 16, 1);
strcpy(namep, RELOC("linux,phandle"));
mem_start = (unsigned long)namep + strlen(namep) + 1;
- RELOC(dt_string_end) = mem_start;
/* Build string array */
prom_printf("Building dt strings...\n");
scan_dt_build_strings(root, &mem_start, &mem_end);
+ RELOC(dt_string_end) = mem_start;
/* Build structure */
mem_start = PAGE_ALIGN(mem_start);
@@ -1731,9 +1754,11 @@
hdr->totalsize = RELOC(dt_struct_end) - RELOC(dt_header_start);
hdr->off_dt_struct = RELOC(dt_struct_start) - RELOC(dt_header_start);
hdr->off_dt_strings = RELOC(dt_string_start) - RELOC(dt_header_start);
+ hdr->dt_strings_size = RELOC(dt_string_end) - RELOC(dt_string_start);
hdr->off_mem_rsvmap = ((unsigned long)rsvmap) - RELOC(dt_header_start);
hdr->version = OF_DT_VERSION;
- hdr->last_comp_version = 1;
+ /* Version 16 is not backward compatible */
+ hdr->last_comp_version = 0x10;
/* Reserve the whole thing and copy the reserve map in, we
* also bump mem_reserve_cnt to cause further reservations to
@@ -1788,6 +1813,9 @@
/* does it need fixup ? */
if (prom_getproplen(i2c, "interrupts") > 0)
return;
+
+ prom_printf("fixing up bogus interrupts for u3 i2c...\n");
+
/* interrupt on this revision of u3 is number 0 and level */
interrupts[0] = 0;
interrupts[1] = 1;
Index: linux-work/arch/ppc64/kernel/setup.c
===================================================================
--- linux-work.orig/arch/ppc64/kernel/setup.c 2005-06-01 16:02:28.000000000 +1000
+++ linux-work/arch/ppc64/kernel/setup.c 2005-06-01 16:07:21.000000000 +1000
@@ -10,7 +10,7 @@
* 2 of the License, or (at your option) any later version.
*/
-#undef DEBUG
+#define DEBUG
#include <linux/config.h>
#include <linux/module.h>
Index: linux-work/arch/ppc64/kernel/prom.c
===================================================================
--- linux-work.orig/arch/ppc64/kernel/prom.c 2005-06-01 16:02:28.000000000 +1000
+++ linux-work/arch/ppc64/kernel/prom.c 2005-06-01 16:07:21.000000000 +1000
@@ -15,7 +15,7 @@
* 2 of the License, or (at your option) any later version.
*/
-#undef DEBUG
+#define DEBUG
#include <stdarg.h>
#include <linux/config.h>
@@ -635,26 +635,32 @@
* unflatten the tree
*/
static int __init scan_flat_dt(int (*it)(unsigned long node,
- const char *full_path, void *data),
+ const char *uname, int depth, void *data),
void *data)
{
unsigned long p = ((unsigned long)initial_boot_params) +
initial_boot_params->off_dt_struct;
int rc = 0;
+ int depth = -1;
do {
u32 tag = *((u32 *)p);
char *pathp;
p += 4;
- if (tag == OF_DT_END_NODE)
+ if (tag == OF_DT_END_NODE) {
+ depth --;
+ continue;
+ }
+ if (tag == OF_DT_NOP)
continue;
if (tag == OF_DT_END)
break;
if (tag == OF_DT_PROP) {
u32 sz = *((u32 *)p);
p += 8;
- p = _ALIGN(p, sz >= 8 ? 8 : 4);
+ if (initial_boot_params->version < 0x10)
+ p = _ALIGN(p, sz >= 8 ? 8 : 4);
p += sz;
p = _ALIGN(p, 4);
continue;
@@ -664,9 +670,18 @@
" device tree !\n", tag);
return -EINVAL;
}
+ depth++;
pathp = (char *)p;
p = _ALIGN(p + strlen(pathp) + 1, 4);
- rc = it(p, pathp, data);
+ if ((*pathp) == '/') {
+ char *lp, *np;
+ for (lp = NULL, np = pathp; *np; np++)
+ if ((*np) == '/')
+ lp = np+1;
+ if (lp != NULL)
+ pathp = lp;
+ }
+ rc = it(p, pathp, depth, data);
if (rc != 0)
break;
} while(1);
@@ -689,13 +704,16 @@
const char *nstr;
p += 4;
+ if (tag == OF_DT_NOP)
+ continue;
if (tag != OF_DT_PROP)
return NULL;
sz = *((u32 *)p);
noff = *((u32 *)(p + 4));
p += 8;
- p = _ALIGN(p, sz >= 8 ? 8 : 4);
+ if (initial_boot_params->version < 0x10)
+ p = _ALIGN(p, sz >= 8 ? 8 : 4);
nstr = find_flat_dt_string(noff);
if (nstr == NULL) {
@@ -713,7 +731,7 @@
}
static void *__init unflatten_dt_alloc(unsigned long *mem, unsigned long size,
- unsigned long align)
+ unsigned long align)
{
void *res;
@@ -727,13 +745,16 @@
static unsigned long __init unflatten_dt_node(unsigned long mem,
unsigned long *p,
struct device_node *dad,
- struct device_node ***allnextpp)
+ struct device_node ***allnextpp,
+ unsigned long fpsize)
{
struct device_node *np;
struct property *pp, **prev_pp = NULL;
char *pathp;
u32 tag;
- unsigned int l;
+ unsigned int l, allocl;
+ int has_name = 0;
+ int new_format = 0;
tag = *((u32 *)(*p));
if (tag != OF_DT_BEGIN_NODE) {
@@ -742,21 +763,62 @@
}
*p += 4;
pathp = (char *)*p;
- l = strlen(pathp) + 1;
+ l = allocl = strlen(pathp) + 1;
*p = _ALIGN(*p + l, 4);
- np = unflatten_dt_alloc(&mem, sizeof(struct device_node) + l,
+ /* version 0x10 has a more compact unit name here instead of the full
+ * path. we accumulate the full path size using "fpsize", we'll rebuild
+ * it later. We detect this because the first character of the name is
+ * not '/'.
+ */
+ if ((*pathp) != '/') {
+ new_format = 1;
+ if (fpsize == 0) {
+ /* root node: special case. fpsize accounts for path
+ * plus terminating zero. root node only has '/', so
+ * fpsize should be 2, but we want to avoid the first
+ * level nodes to have two '/' so we use fpsize 1 here
+ */
+ fpsize = 1;
+ allocl = 2;
+ } else {
+ /* account for '/' and path size minus terminal 0
+ * already in 'l'
+ */
+ fpsize += l;
+ allocl = fpsize;
+ }
+ }
+
+
+ np = unflatten_dt_alloc(&mem, sizeof(struct device_node) + allocl,
__alignof__(struct device_node));
if (allnextpp) {
memset(np, 0, sizeof(*np));
np->full_name = ((char*)np) + sizeof(struct device_node);
- memcpy(np->full_name, pathp, l);
+ if (new_format) {
+ char *p = np->full_name;
+ /* rebuild full path for new format */
+ if (dad && dad->parent) {
+ strcpy(p, dad->full_name);
+#ifdef DEBUG
+ if ((strlen(p) + l + 1) != allocl) {
+ DBG("%s: p: %d, l: %d, a: %d\n",
+ pathp, strlen(p), l, allocl);
+ }
+#endif
+ p += strlen(p);
+ }
+ *(p++) = '/';
+ memcpy(p, pathp, l);
+ } else
+ memcpy(np->full_name, pathp, l);
prev_pp = &np->properties;
**allnextpp = np;
*allnextpp = &np->allnext;
if (dad != NULL) {
np->parent = dad;
- /* we temporarily use the `next' field as `last_child'. */
+ /* we temporarily use the next field as `last_child'*/
if (dad->next == 0)
dad->child = np;
else
@@ -770,18 +832,26 @@
char *pname;
tag = *((u32 *)(*p));
+ if (tag == OF_DT_NOP) {
+ *p += 4;
+ continue;
+ }
if (tag != OF_DT_PROP)
break;
*p += 4;
sz = *((u32 *)(*p));
noff = *((u32 *)((*p) + 4));
- *p = _ALIGN((*p) + 8, sz >= 8 ? 8 : 4);
+ *p += 8;
+ if (initial_boot_params->version < 0x10)
+ *p = _ALIGN(*p, sz >= 8 ? 8 : 4);
pname = find_flat_dt_string(noff);
if (pname == NULL) {
printk("Can't find property name in list !\n");
break;
}
+ if (strcmp(pname, "name") == 0)
+ has_name = 1;
l = strlen(pname) + 1;
pp = unflatten_dt_alloc(&mem, sizeof(struct property),
__alignof__(struct property));
@@ -801,6 +871,28 @@
}
*p = _ALIGN((*p) + sz, 4);
}
+ /* with version 0x10 we may not have the name property, recreate
+ * it here from the unit name if absent
+ */
+ if (!has_name) {
+ char *pa = pathp;
+ int sz;
+
+ while (*pa && (*pa) != '@')
+ pa++;
+ sz = (pa - pathp) + 1;
+ pp = unflatten_dt_alloc(&mem, sizeof(struct property) + sz,
+ __alignof__(struct property));
+ if (allnextpp) {
+ pp->name = "name";
+ pp->length = sz;
+ pp->value = (unsigned char *)(pp + 1);
+ *prev_pp = pp;
+ prev_pp = &pp->next;
+ memcpy(pp->value, pathp, sz - 1);
+ ((char *)pp->value)[sz - 1] = 0;
+ }
+ }
if (allnextpp) {
*prev_pp = NULL;
np->name = get_property(np, "name", NULL);
@@ -812,7 +904,7 @@
np->type = "<NULL>";
}
while (tag == OF_DT_BEGIN_NODE) {
- mem = unflatten_dt_node(mem, p, np, allnextpp);
+ mem = unflatten_dt_node(mem, p, np, allnextpp, fpsize);
tag = *((u32 *)(*p));
}
if (tag != OF_DT_END_NODE) {
@@ -842,7 +934,7 @@
/* First pass, scan for size */
start = ((unsigned long)initial_boot_params) +
initial_boot_params->off_dt_struct;
- size = unflatten_dt_node(0, &start, NULL, NULL);
+ size = unflatten_dt_node(0, &start, NULL, NULL, 0);
DBG(" size is %lx, allocating...\n", size);
@@ -854,7 +946,7 @@
/* Second pass, do actual unflattening */
start = ((unsigned long)initial_boot_params) +
initial_boot_params->off_dt_struct;
- unflatten_dt_node(mem, &start, NULL, &allnextp);
+ unflatten_dt_node(mem, &start, NULL, &allnextp, 0);
if (*((u32 *)start) != OF_DT_END)
printk(KERN_WARNING "Weird tag at end of tree: %x\n", *((u32 *)start));
*allnextp = NULL;
@@ -880,7 +972,7 @@
static int __init early_init_dt_scan_cpus(unsigned long node,
- const char *full_path, void *data)
+ const char *uname, int depth, void *data)
{
char *type = get_flat_dt_prop(node, "device_type", NULL);
u32 *prop;
@@ -933,13 +1025,15 @@
}
static int __init early_init_dt_scan_chosen(unsigned long node,
- const char *full_path, void *data)
+ const char *uname, int depth, void *data)
{
u32 *prop;
u64 *prop64;
extern unsigned long memory_limit, tce_alloc_start, tce_alloc_end;
- if (strcmp(full_path, "/chosen") != 0)
+ DBG("search \"chosen\", depth: %d, uname: %s\n", depth, uname);
+
+ if (depth != 1 || strcmp(uname, "chosen") != 0)
return 0;
/* get platform type */
@@ -989,18 +1083,20 @@
}
static int __init early_init_dt_scan_root(unsigned long node,
- const char *full_path, void *data)
+ const char *uname, int depth, void *data)
{
u32 *prop;
- if (strcmp(full_path, "/") != 0)
+ if (depth != 0)
return 0;
prop = (u32 *)get_flat_dt_prop(node, "#size-cells", NULL);
dt_root_size_cells = (prop == NULL) ? 1 : *prop;
-
+ DBG("dt_root_size_cells = %x\n", dt_root_size_cells);
+
prop = (u32 *)get_flat_dt_prop(node, "#address-cells", NULL);
dt_root_addr_cells = (prop == NULL) ? 2 : *prop;
+ DBG("dt_root_addr_cells = %x\n", dt_root_addr_cells);
/* break now */
return 1;
@@ -1028,7 +1124,7 @@
static int __init early_init_dt_scan_memory(unsigned long node,
- const char *full_path, void *data)
+ const char *uname, int depth, void *data)
{
char *type = get_flat_dt_prop(node, "device_type", NULL);
cell_t *reg, *endp;
@@ -1044,7 +1140,9 @@
endp = reg + (l / sizeof(cell_t));
- DBG("memory scan node %s ...\n", full_path);
+ DBG("memory scan node %s ..., reg size %ld, data: %x %x %x %x, ...\n",
+ uname, l, reg[0], reg[1], reg[2], reg[3]);
+
while ((endp - reg) >= (dt_root_addr_cells + dt_root_size_cells)) {
unsigned long base, size;
@@ -1455,10 +1553,11 @@
struct device_node *np = allnodes;
read_lock(&devtree_lock);
- for (; np != 0; np = np->allnext)
+ for (; np != 0; np = np->allnext) {
if (np->full_name != 0 && strcasecmp(np->full_name, path) == 0
&& of_node_get(np))
break;
+ }
read_unlock(&devtree_lock);
return np;
}
Index: linux-work/include/asm-ppc64/prom.h
===================================================================
--- linux-work.orig/include/asm-ppc64/prom.h 2005-06-01 16:07:18.000000000 +1000
+++ linux-work/include/asm-ppc64/prom.h 2005-06-01 16:07:21.000000000 +1000
@@ -22,13 +22,15 @@
#define RELOC(x) (*PTRRELOC(&(x)))
/* Definitions used by the flattened device tree */
-#define OF_DT_HEADER 0xd00dfeed /* 4: version, 4: total size */
-#define OF_DT_BEGIN_NODE 0x1 /* Start node: full name */
+#define OF_DT_HEADER 0xd00dfeed /* marker */
+#define OF_DT_BEGIN_NODE 0x1 /* Start of node, full name */
#define OF_DT_END_NODE 0x2 /* End node */
-#define OF_DT_PROP 0x3 /* Property: name off, size, content */
+#define OF_DT_PROP 0x3 /* Property: name off, size,
+ * content */
+#define OF_DT_NOP 0x4 /* nop */
#define OF_DT_END 0x9
-#define OF_DT_VERSION 1
+#define OF_DT_VERSION 0x10
/*
* This is what gets passed to the kernel by prom_init or kexec
@@ -54,7 +56,9 @@
u32 version; /* format version */
u32 last_comp_version; /* last compatible version */
/* version 2 fields below */
- u32 boot_cpuid_phys; /* Which physical CPU id we're booting on */
+ u32 boot_cpuid_phys; /* Physical CPU id we're booting on */
+ /* version 3 fields below */
+ u32 dt_strings_size; /* size of the DT strings block */
};
^ permalink raw reply
* Booting the linux-ppc64 kernel & flattened device tree v0.4
From: Benjamin Herrenschmidt @ 2005-06-01 8:26 UTC (permalink / raw)
To: linuxppc-embedded, u-boot-users, linuxppc-dev list,
linuxppc64-dev
DO NOT REPLY TO ALL LISTS PLEASE ! (and CC me on replies).
Here's the fourth version of my document along with new kernel patches
for the new improved flattened format, and the first release of the
device-tree "compiler" tool. The patches will be posted as a reply to
this email. The compiler, dtc, can be downloaded, the URL is in the
document.
---
Booting the Linux/ppc64 kernel without Open Firmware
----------------------------------------------------
(c) 2005 Benjamin Herrenschmidt <benh@kernel.crashing.org>, IBM Corp.
May 18, 2005: Rev 0.1 - Initial draft, no chapter III yet.
May 19, 2005: Rev 0.2 - Add chapter III and bits & pieces here or
clarifies the fact that a lot of things are
optional, the kernel only requires a very
small device tree, though it is encouraged
to provide an as complete one as possible.
May 24, 2005: Rev 0.3 - Precise that DT block has to be in RAM
- Misc fixes
- Define version 3 and new format version 16
for the DT block (version 16 needs kernel
patches, will be fwd separately).
String block now has a size, and full path
is replaced by unit name for more
compactness.
linux,phandle is made optional, only nodes
that are referenced by other nodes need it.
"name" property is now automatically
deduced from the unit name
June 1, 2005: Rev 0.4 - Correct confusion between OF_DT_END and
OF_DT_END_NODE in structure definition.
- Change version 16 format to always align
property data to 4 bytes. Since tokens are
already aligned, that means no specific
required alignement between property size
and property data. The old style variable
alignment would make it impossible to do
"simple" insertion of properties using
memove (thanks Milton for
noticing). Updated kernel patch as well
- Correct a few more alignement constraints
- Add a chapter about the device-tree
compiler and the textural representation of
the tree that can be "compiled" by dtc.
ToDo:
- Add some definitions of interrupt tree (simple/complex)
- Add some definitions for pci host bridges
I- Introduction
===============
During the recent developpements of the Linux/ppc64 kernel, and more
specifically, the addition of new platform types outside of the old
IBM pSeries/iSeries pair, it was decided to enforce some strict rules
regarding the kernel entry and bootloader <-> kernel interfaces, in
order to avoid the degeneration that has become the ppc32 kernel entry
point and the way a new platform should be added to the kernel. The
legacy iSeries platform breaks those rules as it predates this scheme,
but no new board support will be accepted in the main tree that
doesn't follows them properly.
The main requirement that will be defined in more details below is
the presence of a device-tree whose format is defined after Open
Firmware specification. However, in order to make life easier
to embedded board vendors, the kernel doesn't require the device-tree
to represent every device in the system and only requires some nodes
and properties to be present. This will be described in details in
section III, but, for example, the kernel does not require you to
create a node for every PCI device in the system. It is a requirement
to have a node for PCI host bridges in order to provide interrupt
routing informations and memory/IO ranges, among others. It is also
recommended to define nodes for on chip devices and other busses that
doesn't specifically fit in an existing OF specification, like on chip
devices, this creates a great flexibility in the way the kernel can
them probe those and match drivers to device, without having to hard
code all sorts of tables. It also makes it more flexible for board
vendors to do minor hardware upgrades without impacting significantly
the kernel code or cluttering it with special cases.
1) Entry point
--------------
There is one and one single entry point to the kernel, at the start
of the kernel image. That entry point support two calling
conventions:
a) Boot from Open Firmware. If your firmware is compatible
with Open Firmware (IEEE 1275) or provides an OF compatible
client interface API (support for "interpret" callback of
forth words isn't required), you can enter the kernel with:
r5 : OF callback pointer as defined by IEEE 1275
bindings to powerpc. Only the 32 bits client interface
is currently supported
r3, r4 : address & lenght of an initrd if any or 0
MMU is either on or off, the kernel will run the
trampoline located in arch/ppc64/kernel/prom_init.c to
extract the device-tree and other informations from open
firmware and build a flattened device-tree as described
in b). prom_init() will then re-enter the kernel using
the second method. This trampoline code runs in the
context of the firmware, which is supposed to handle all
exceptions during that time.
b) Direct entry with a flattened device-tree block. This entry
point is called by a) after the OF trampoline and can also be
called directly by a bootloader that does not support the Open
Firmware client interface. It is also used by "kexec" to
implement "hot" booting of a new kernel from a previous
running one. This method is what I will describe in more
details in this document, as method a) is simply standard Open
Firmware, and thus should be implemented according to the
various standard documents defining it and it's binding to the
PowerPC platform. The entry point definition then becomes:
r3 : physical pointer to the device-tree block
(defined in chapter II) in RAM
r4 : physical pointer to the kernel itself. This is
used by the assembly code to properly disable the MMU
in case you are entering the kernel with MMU enabled
and a non-1:1 mapping.
r5 : NULL (as to differenciate with method a)
Note about SMP entry: Either your firmware puts your other
CPUs in some sleep loop or spin loop in ROM where you can get
them out via a soft reset or some other mean, in which case
you don't need to care, or you'll have to enter the kernel
with all CPUs. The way to do that with method b) will be
described in a later revision of this document.
2) Board support
----------------
Board supports (platforms) are not exclusive config options. An
arbitrary set of board supports can be built in a single kernel
image. The kernel will "known" what set of functions to use for a
given platform based on the content of the device-tree. Thus, you
should:
a) add your platform support as a _boolean_ option in
arch/ppc64/Kconfig, following the example of PPC_PSERIES,
PPC_PMAC and PPC_MAPLE. The later is probably a good
example of a board support to start from.
b) create your main platform file as
"arch/ppc64/kernel/myboard_setup.c" and add it to the Makefile
under the condition of your CONFIG_ option. This file will
define a structure of type "ppc_md" containing the various
callbacks that the generic code will use to get to your
platform specific code
c) Add a reference to your "ppc_md" structure in the
"machines" table in arch/ppc64/kernel/setup.c
d) request and get assigned a platform number (see PLATFORM_*
constants in include/asm-ppc64/processor.h
I will describe later the boot process and various callbacks that
your platform should implement.
II - The DT block format
===========================
This chapter defines the actual format of the flattened device-tree
passed to the kernel. The actual content of it and kernel requirements
are described later. You can find example of code manipulating that
format in various places, including arch/ppc64/kernel/prom_init.c
which will generate a flattened device-tree from the Open Firmware
representation, or the fs2dt utility which is part of the kexec tools
which will generate one from a filesystem representation. It is
expected that a bootloader like uboot provides a bit more support,
that will be discussed later as well.
Note: The block has to be in main memory. It has to be accessible in
both real mode and virtual mode with no other mapping than main
memory. If you are writing a simple flash bootloader, it should copy
the block to RAM before passing it to the kernel.
1) Header
---------
The kernel is entered with r3 pointing to an area of memory that is
roughtly described in include/asm-ppc64/prom.h by the structure
boot_param_header:
struct boot_param_header
{
u32 magic; /* magic word OF_DT_HEADER */
u32 totalsize; /* total size of DT block */
u32 off_dt_struct; /* offset to structure */
u32 off_dt_strings; /* offset to strings */
u32 off_mem_rsvmap; /* offset to memory reserve map */
u32 version; /* format version */
u32 last_comp_version; /* last compatible version */
/* version 2 fields below */
u32 boot_cpuid_phys; /* Which physical CPU id we're
booting on */
/* version 3 fields below */
u32 size_dt_strings; /* size of the strings block */
};
Along with the constants:
/* Definitions used by the flattened device tree */
#define OF_DT_HEADER 0xd00dfeed /* 4: version, 4: total size */
#define OF_DT_BEGIN_NODE 0x1 /* Start node: full name */
#define OF_DT_END_NODE 0x2 /* End node */
#define OF_DT_PROP 0x3 /* Property: name off,
size, content */
#define OF_DT_END 0x9
All values in this header are in big endian format, the various
fields in this header are defined more precisely below. All
"offsets" values are in bytes from the start of the header, that is
from r3 value.
- magic
This is a magic value that "marks" the beginning of the
device-tree block header. It contains the value 0xd00dfeed and is
defined by the constant OF_DT_HEADER
- totalsize
This is the total size of the DT block including the header. The
"DT" block should enclose all data structures defined in this
chapter (who are pointed to by offsets in this header). That is,
the device-tree structure, strings, and the memory reserve map.
- off_dt_struct
This is an offset from the beginning of the header to the start
of the "structure" part the device tree. (see 2) device tree)
- off_dt_strings
This is an offset from the beginning of the header to the start
of the "strings" part of the device-tree
- off_mem_rsvmap
This is an offset from the beginning of the header to the start
of the reserved memory map. This map is a list of pairs of 64
bits integers. Each pair is a physical address and a size. The
list is terminated by an entry of size 0. This map provides the
kernel with a list of physical memory areas that are "reserved"
and thus not to be used for memory allocations, especially during
early initialisation. The kernel needs to allocate memory during
boot for things like un-flattening the device-tree, allocating an
MMU hash table, etc... Those allocations must be done in such a
way to avoid overriding critical things like, on Open Firmware
capable machines, the RTAS instance, or on some pSeries, the TCE
tables used for the iommu. Typically, the reserve map should
contain _at least_ this DT block itself (header,total_size). If
you are passing an initrd to the kernel, you should reserve it as
well. You do not need to reserve the kernel image itself. The map
should be 64 bits aligned.
- version
This is the version of this structure. Version 1 stops
here. Version 2 adds an additional field boot_cpuid_phys.
Version 3 adds the size of the strings block, allowing the kernel
to reallocate it easily at boot and free up the unused flattened
structure after expansion.
Version 16 introduces a new more "compact" format for the tree
itself that is however not backward compatible.
You should always generate a structure of the highest version defined
at the time of your implementation. Currently that is version 16,
unless you explicitely aim at being backward compatible
- last_comp_version
Last compatible version. This indicates down to what version of
the DT block you are backward compatible with. For example,
version 2 is backward compatible with version 1 (that is, a
kernel build for version 1 will be able to boot with a version 2
format). You should put a 1 in this field if you generate a
device tree of version 1 to 3, or 0x10 if you generate a tree of
version 0x10 using the new unit name format.
- boot_cpuid_phys
This field only exist on version 2 headers. It indicate which
physical CPU ID is calling the kernel entry point. This is used,
among others, by kexec. If you are on an SMP system, this value
should match the content of the "reg" property of the CPU node in
the device-tree corresponding to the CPU calling the kernel entry
point (see further chapters for more informations on the required
device-tree contents)
So the typical layout of a DT block (though the various parts don't
need to be in that order) looks like (addresses go from top to bottom):
------------------------------
r3 -> | struct boot_param_header |
------------------------------
| (alignment gap) (*) |
------------------------------
| memory reserve map |
------------------------------
| (alignment gap) |
------------------------------
| |
| device-tree structure |
| |
------------------------------
| (alignment gap) |
------------------------------
| |
| device-tree strings |
| |
-----> ------------------------------
|
|
--- (r3 + totalsize)
(*) The alignment gaps are not necessarily present, their presence
and size are dependent on the various alignment requirements of
the individual data blocks.
2) Device tree generalities
---------------------------
This device-tree itself is separated in two different blocks, a
structure block and a strings block. Both need to be aligned to a 4
bytes boundary.
First, let's quickly describe the device-tree concept before detailing
the storage format. This chapter does _not_ describe the detail of the
required types of nodes & properties for the kernel, this is done
later in chapter III.
The device-tree layout is strongly inherited from the definition of
the Open Firmware IEEE 1275 device-tree. It's basically a tree of
nodes, each node having two or more named properties. A property can
have a value or not.
It is a tree, so each node has one and only one parent except for the
root node who has no parent.
A node has 2 names. The actual node name is generally contained in a
property of type "name" in the node property list whose value is a
zero terminated string and is mandatory for version 1 to 3 of the
format definition (as it is in Open Firmware). Version 0x10 makes it
optional as it can generate it from the unit name defined below.
There is also a "unit name" that is used to differenciate nodes with
the same name at the same level, it is usually made of the node
name's, the "@" sign, and a "unit address", which definition is
specific to the bus type the node sits on.
The unit name doesn't exist as a property per-se but is included in the
device-tree structure. It is typically used to represent "path" in the
device-tree. More details about the actual format of these will be
below.
The kernel ppc64 generic code does not make any formal use of the unit
address (though some board support code may do) so the only real
requirement here for the unit address is to ensure uniqueness of
the node unit name at a given level of the tree. Nodes with no notion
of address and no possible sibling of the same name (like /memory or
/cpus) may ommit the unit address in the context of this
specification, or use the "@0" default unit address.
The unit name is used to define a node "full path", which is the
concatenation of all parent nodes unit names separated with "/".
The root node doesn't have a defined name, and isn't required to have
a name property either if you are using version 3 or earlier of the
format. It also has no unit address (no @ symbol followed by a unit
address). The root node unit name is thus an empty string. The full
path to the root node is "/"
Every node who actually represents an actual device (that is who isn't
only a virtual "container" for more nodes, like "/cpus" is) is also
required to have a "device_type" property indicating the type of node
Finally, every node that can be referrenced from a property in another
node is required to have a "linux,phandle" property. Real open
firmware implementations do provide a unique "phandle" value for every
node that the "prom_init()" trampoline code turns into
"linux,phandle" properties. However, this is made optional if the
flattened is used directly. An example of a node referencing another
node via "phandle" is when laying out the interrupt tree which will be
described in a further version of this document.
This propery is a 32 bits value that uniquely identify a node. You are
free to use whatever values or system of values, internal pointers, or
whatever to generate these, the only requirement is that every node
for which you provide that property has a unique value for it.
Here is an example of a simple device-tree. In this example, a "o"
designates a node followed by the node unit name. Properties are
presented with their name followed by their content. "content"
represent an ASCII string (zero terminated) value, while <content>
represent a 32 bits hexadecimal value. The various nodes in this
example will be discusse in a later chapter. At this point, it is
only meant to give you a idea of what a device-tree looks like. I have
on purpose kept the "name" and "linux,phandle" properties which aren't
necessary in order to give you a better idea of what the tree looks
like in practice.
/ o device-tree
|- name = "device-tree"
|- model = "MyBoardName"
|- compatible = "MyBoardFamilyName"
|- #address-cells = <2>
|- #size-cells = <2>
|- linux,phandle = <0>
|
o cpus
| | - name = "cpus"
| | - linux,phandle = <1>
| | - #address-cells = <1>
| | - #size-cells = <0>
| |
| o PowerPC,970@0
| |- name = "PowerPC,970"
| |- device_type = "cpu"
| |- reg = <0>
| |- clock-frequency = <5f5e1000>
| |- linux,boot-cpu
| |- linux,phandle = <2>
|
o memory@0
| |- name = "memory"
| |- device_type = "memory"
| |- reg = <00000000 00000000 00000000 20000000>
| |- linux,phandle = <3>
|
o chosen
|- name = "chosen"
|- bootargs = "root=/dev/sda2"
|- linux,platform = <00000600>
|- linux,phandle = <4>
This tree is almost a minimal tree. It pretty much contains the
minimal set of required nodes and properties to boot a linux kernel,
that is some basic model informations at the root, the CPUs, the
physical memory layout, and misc informations passed through /chosen
like in this example, the platform type (mandatory) and the kernel
command line arguments (optional).
The /cpus/PowerPC,970@0/linux,boot-cpu property is an example of a
property without a value. All other properties have a value. The
signification of the #address-cells and #size-cells properties will be
explained in chapter IV which defines precisely the required nodes and
properties and their content.
3) Device tree "structure" block
The structure of the device tree is a linearized tree structure. The
"OF_DT_BEGIN_NODE" token starts a new node, and the "OF_DT_END_NODE" ends
that node definition. Child nodes are simply defined before
"OF_DT_END_NODE" (that is nodes within the node). A 'token' is a 32
bits value. The tree has to be "finished" with a OF_DT_END token
Here's the basic structure of a single node:
* token OF_DT_BEGIN_NODE (that is 0x00000001)
* for version 1 to 3, this is the node full path as a zero
terminated string, starting with "/". For version 16 and later,
this is the node unit name only (or an empty string for the
root node)
* [align gap to next 4 bytes boundary]
* for each property:
* token OF_DT_PROP (that is 0x00000003)
* 32 bits value of property value size in bytes (or 0 of no value)
* 32 bits value of offset in string block of property name
* property value data if any
* [align gap to next 4 bytes boundary]
* [child nodes if any]
* token OF_DT_END_NODE (that is 0x00000002)
So the node content can be summmarised as a start token, a full path, a list of
properties, a list of child node and an end token. Every child node is
a full node structure itself as defined above
4) Device tree 'strings" block
In order to save space, property names, which are generally redundant,
are stored separately in the "strings" block. This block is simply the
whole bunch of zero terminated strings for all property names
concatenated together. The device-tree property definitions in the
structure block will contain offset values from the beginning of the
strings block.
III - Required content of the device tree
=========================================
WARNING: All "linux,*" properties defined in this document apply only
to a flattened device-tree. If your platform uses a real
implementation of Open Firmware or an implementation compatible with
the Open Firmware client interface, those properties will be created
by the trampoline code in the kernel's prom_init() file. For example,
that's where you'll have to add code to detect your board model and
set the platform number. However, when using the flatenned device-tree
entry point, there is no prom_init() pass, and thus you have to
provide those properties yourself.
1) Note about cells and address representation
----------------------------------------------
The general rule is documented in the various Open Firmware
documentations. If you chose to describe a bus with the device-tree
and there exist an OF bus binding, then you should follow the
specification. However, the kernel does not require every single
device or bus to be described by the device tree.
In general, the format of an address for a device is defined by the
parent bus type, based on the #address-cells and #size-cells property. In
absence of such a property, the parent's parent values are used,
etc... The kernel requires the root node to have those properties
defining addresses format for devices directly mapped on the processor
bus.
Those 2 properties define 'cells' for representing an address and a
size. A "cell" is a 32 bits number. For example, if both contain 2
like the example tree given above, then an address and a size are both
composed of 2 cells, that is a 64 bits number (cells are concatenated
and expected to be in big endian format). Another example is the way
Apple firmware define them, that is 2 cells for an address and one
cell for a size.
A device IO or MMIO areas on the bus are defined in the "reg"
property. The format of this property depends on the bus the device is
sitting on. Standard bus types define their "reg" properties format in
the various OF bindings for those bus types, you are free to define
your own "reg" format for proprietary busses or virtual busses
enclosing on-chip devices, though it is recommended that the parts of
the "reg" property containing addresses and sizes do respect the
defined #address-cells and #size-cells when those make sense.
Later, I will define more precisely some common address formats.
For a new ppc64 board, I recommend to use either the 2/2 format or
Apple's 2/1 format which is slightly more compact since sizes usually
fit in a single 32 bits word.
2) Note about "compatible" properties
-------------------------------------
Those properties are optional, but recommended in devices and the root
node. The format of a "compatible" property is a list of concatenated
zero terminated strings. They allow a device to express it's
compatibility with a family of similar devices, in some cases,
allowing a single driver to match against several devices regardless
of their actual names
3) Note about "name" properties
-------------------------------
While earlier users of Open Firmware like OldWorld macintoshes tended
to use the actual device name for the "name" property, it's nowadays
considered a good practice to use a name that is closer to the device
class (often equal to device_type). For example, nowadays, ethernet
controllers are named "ethernet", an additional "model" property
defining precisely the chip type/model, and "compatible" property
defining the family in case a single driver can driver more than one
of these chips. The kernel however doesn't generally put any
restriction on the "name" property, it is simply considered good
practice to folow the standard and it's evolutions as closely as
possible.
Note also that the new format version 16 makes the "name" property
optional. If it's absent for a node, then the node's unit name is then
used to reconstruct the name. That is, the part of the unit name
before the "@" sign is used (or the entire unit name if no "@" sign
is present).
4) Note about node and property names and character set
-------------------------------------------------------
While open firmware provides more flexibe usage of 8859-1, this
specification enforces more strict rules. Nodes and properties should
be comprised only of ASCII characters 'a' to 'z', '0' to
'9', ',', '.', '_', '+', '#', '?', and '-'. Node names additionally
allow uppercase characters 'A' to 'Z' (property names should be
lowercase. The fact that vendors like Apple don't respect this rule is
irrelevant here).
Additionally, node and property names should always begin with a
character in the range 'a' to 'z' (or 'A' to 'Z' for node names).
The maximum number of characters for both nodes and property names
is 31. In the case of node names, this is only the leftmost part of
a unit name (the pure "name" property), it doesn't include the unit
address which can extend beyond that limit.
5) Required nodes and properties
--------------------------------
a) The root node
The root node requires some properties to be present:
- model : this is your board name/model
- #address-cells : address representation for "root" devices
- #size-cells: the size representation for "root" devices
Additionally, some recommended properties are:
- compatible : the board "family" generally finds its way here,
for example, if you have 2 board models with a similar layout,
that typically get driven by the same platform code in the
kernel, you would use a different "model" property but put a
value in "compatible". The kernel doesn't directly use that
value (see /chosen/linux,platform for how the kernel choses a
platform type) but it is generally useful.
It's also generally where you add additional properties specific
to your board like the serial number if any, that sort of thing. it
is recommended that if you add any "custom" property whose name may
clash with standard defined ones, you prefix them with your vendor
name and a comma.
b) The /cpus node
This node is the parent of all individual CPUs nodes. It doesn't
have any specific requirements, though it's generally good practice
to have at least:
#address-cells = <00000001>
#size-cells = <00000000>
This defines that the "address" for a CPU is a single cell, and has
no meaningful size. This is not necessary but the kernel will assume
that format when reading the "reg" properties of a CPU node, see
below
c) The /cpus/* nodes
So under /cpus, you are supposed to create a node for every CPU on
the machine. There is no specific restriction on the name of the
CPU, though It's common practice to call it PowerPC,<name>, for
example, Apple uses PowerPC,G5 while IBM uses PowerPC,970FX.
Required properties:
- device_type : has to be "cpu"
- reg : This is the physical cpu number, it's single 32 bits cell,
this is also used as-is as the unit number for constructing the
unit name in the full path, for example, with 2 CPUs, you would
have the full path:
/cpus/PowerPC,970FX@0
/cpus/PowerPC,970FX@1
(unit addresses do not require to have leading zero's)
- d-cache-line-size : one cell, L1 data cache line size in bytes
- i-cache-line-size : one cell, L1 instruction cache line size in bytes
- d-cache-size : one cell, size of L1 data cache in bytes
- i-cache-size : one cell, size of L1 instruction cache in bytes
Recommended properties:
- timebase-frequency : a cell indicating the frequency of the
timebase in Hz. This is not directly used by the generic code,
but you are welcome to copy/paste the pSeries code for setting
the kernel timebase/decrementer calibration based on this value.
- clock-frequency : a cell indicating the CPU core clock frequency
in Hz. A new property will be defined for 64 bits value, but if
your frequency is < 4Ghz, one cell is enough. Here as well as
for the above, the common code doesn't use that property, but
you are welcome to re-use the pSeries or Maple one. A future
kernel version might provide a common function for this.
You are welcome to add any property you find relevant to your board,
like some informations about mecanism used to soft-reset the CPUs
for example (Apple puts the GPIO number for CPU soft reset lines in
there as a "soft-reset" property as they start secondary CPUs by
soft-resetting them).
d) the /memory node(s)
To define the physical memory layout of your board, you should
create one or more memory node(s). You can either create a single
node with all memory ranges in it's reg property, or you can create
several nodes, as you wishes. The unit address (@ part) used for the
full path is the address of the first range of memory defined by a
given node. If you use a single memory node, this will typically be
@0.
Required properties:
- device_type : has to be "memory"
- reg : This property contain all the physical memory ranges of
your board. It's a list of addresses/sizes concatenated
together, the number of cell of those beeing defined by the
#address-cells and #size-cells of the root node. For example,
with both of these properties beeing 2 like in the example given
earlier, a 970 based machine with 6Gb of RAM could typically
have a "reg" property here that looks like:
00000000 00000000 00000000 80000000
00000001 00000000 00000001 00000000
That is a range starting at 0 of 0x80000000 bytes and a range
starting at 0x100000000 and of 0x100000000 bytes. You can see
that there is no memory covering the IO hold between 2Gb and
4Gb. Some vendors prefer splitting those ranges into smaller
segments, the kernel doesn't care.
c) The /chosen node
This node is a bit "special". Normally, that's where open firmware
puts some variable environment informations, like the arguments, or
phandle pointers to nodes like the main interrupt controller, or the
default input/output devices.
This specification makes a few of these mandatory, but also defines
some linux specific properties that would be normally constructed by the
prom_init() trampoline when booting with an OF client interface, but
that you have to provide yourself when using the flattened format.
Required properties:
- linux,platform : This is your platform number as assigned by the
architecture maintainers
Recommended properties:
- bootargs : This zero terminated string is passed as the kernel
command line
- linux,stdout-path : This is the full path to your standard
console device if any. Typically, if you have serial devices on
your board, you may want to put the full path to the one set as
the default console in the firmware here, for the kernel to pick
it up as it's own default console. If you look at the funciton
set_preferred_console() in arch/ppc64/kernel/setup.c, you'll see
that the kernel tries to find out the default console and has
knowledge of various types like 8250 serial ports. You may want
to extend this function to add your own.
- interrupt-controller : This is one cell containing a phandle
value that matches the "linux,phandle" property of your main
interrupt controller node. May be used for interrupt routing.
This is all that is currently required. However, it is strongly
recommended that you expose PCI host bridges as documented in the
PCI binding to open firmware, and your interrupt tree as documented
in OF interrupt tree specification.
IV - "dtc", the device tree compiler
====================================
dtc source code can be found at <http://ozlabs.org/~dgibson/dtc/dtc.tar.gz>
WARNING: This version is still in early developpement stage, the
resulting device-tree "blobs" have not yet been validated with the
kernel. The current generated bloc lacks a useful reserve map (it will
be fixed to generate an empty one, it's up to the bootloader to fill
it up) among others. The error handling needs work, bugs are lurking, etc...
dtc basically takes a device-tree in a given format and outputs a
device-tree in another format. The currently supported formats are:
Input formats:
-------------
- "dtb": "blob" format, that is a flattened device-tree block with
header all in a binary blob.
- "dts": "source" format. This is a text file containing a
"source" for a device-tree. The format is defined later in this
chapter.
- "fs" format. This is a representation equivalent to the
output of /proc/device-tree, that is nodes are directories and
properties are files
Output formats:
---------------
- "dtb": "blob" format
- "dts": "source" format
- "asm": assembly language file. This is a file that can be
sourced by gas to generate a device-tree "blob". That file can
then simply be added to your Makefile. Additionally, the
assembly file exports some symbols that can be use
The syntax of the dtc tool is
dtc [-I <input-format>] [-O <output-format>]
[-o output-filename] [-V output_version] input_filename
The "output_version" defines what versio of the "blob" format will be
generated. Supported versions are 1,2,3 and 16. The default is
currently version 3 but that may change in the future to version 16.
Additionally, dtc performs various sanity checks on the tree, like the
uniqueness of linux,phandle properties, validity of strings, etc...
The format of the .dts "source" file is "C" like, supports C and C++
style commments.
/ {
}
The above is the "device-tree" definition. It's the only statement
supported currently at the toplevel.
/ {
property1 = "string_value"; /* define a property containing a 0
* terminated string
*/
property2 = <1234abcd>; /* define a property containing a
* numerical 32 bits value (hexadecimal)
*/
property3 = <12345678 12345678 deadbeef>;
/* define a property containing 3 numerical
* 32 bits values (cells) in
* hexadecimal
*/
property4 = [0a 0b 0c 0d de ea ad be ef];
/* define a property whose content is
* an arbitrary array of bytes
*/
childnode@addresss { /* define a child node named "childnode"
* whose unit name is "childnode@address"
*/
childprop = "hello\n"; /* define a property "childprop" of
* childnode (in this case, a string)
*/
};
};
Nodes can contain other nodes etc... thus defining the hierarchical
structure of the tree.
Strings support common escape sequences from C: "\n", "\t", "\r",
"\(octal value)", "\x(hex value)".
It is also suggested that you pipe your source file through cpp (gcc
preprocessor) so you can use #include's, #define for constants, etc...
Finally, various options are planned but not yet implemented, like
automatic generation of phandles, labels (exported to the asm file so
you can point to a property content and change it easily from whatever
you link the device-tree with), label or path instead of numeric value
in some cells to "point" to a node (replaced by a phandle at compile
time), export of reserve map address to the asm file, ability to
specify reserve map content at compile time, etc...
We may provide a .h include file with common definitions of that
proves useful for some properties (like building PCI properties or
interrupt maps) though it may be better to add a notion of struct
definitions to the compiler...
V - Recommendation for a bootloader
===================================
Here are some various ideas/recommendations that have been proposed
while all this has been defined and implemented.
- A very The bootloader may want to be able to use the device-tree
itself and may want to manipulate it (to add/edit some properties,
like physical memory size or kernel arguments). At this point, 2
choices can be made. Either the bootloader works directly on the
flattened format, or the bootloader has it's own internal tree
representation with pointers (similar to the kernel one) and
re-flattens the tree when booting the kernel. The former is a bit
more difficult to edit/modify, the later requires probably a bit
more code to handle the tree structure. Note that the structure
format has been designed so it's relatively easy to "insert"
properties or nodes or delete them by just memmovin'g things
around. It contains no internal offsets or pointers for this purpose.
- An example of code for iterating nodes & retreiving properties
directly from the flattened tree format can be found in the kernel
file arch/ppc64/kernel/prom.c, look at scan_flat_dt() function,
it's usage in early_init_devtree(), and the corresponding various
early_init_dt_scan_*() callbacks. That code can be re-used in a
GPL bootloader, and as the author of that code, I would be happy
do discuss possible free licencing to any vendor who wishes to
integrate all or part of this code into a non-GPL bootloader.
^ permalink raw reply
* Re: Newbie question on Linux-PPC
From: Wolfgang Denk @ 2005-06-01 8:05 UTC (permalink / raw)
To: Srivatsan CR; +Cc: linuxppc-embedded
In-Reply-To: <3B58B875DBDE504F94D2A1A1C9DF6F1FD00500@bglnt005.asia.ad.flextronics.com>
In message <3B58B875DBDE504F94D2A1A1C9DF6F1FD00500@bglnt005.asia.ad.flextronics.com> you wrote:
> I am having a MPC8260 based board with the following memory map.
>
> Device Start address End address
> EPROM 0x00000000 0x03FFFFFF
> SDRAM 0x04000000 0x13FFFFFF
>
> I have a doubt regarding Linux Port onto this board. I have read on the web
> that Linux usually expects the SDRAM at 0x0, is it that the porting of linux
> onto this board is totally impossible? If the porting is possible can anyone
No, proting is still possible, it involves just one additional step:
fixong your boot loader to provide a different memory map.
> help me out where to change the memory mapping of Linux for MPC8260?
In your boot loader.
> ------_=_NextPart_001_01C5666C.2B0053B0
> Content-Type: text/html
> Content-Transfer-Encoding: quoted-printable
>
> <html xmlns:o=3D"urn:schemas-microsoft-com:office:office" =
Please don't poost HTML to mailing lists.
Best regards,
Wolfgang Denk
--
Software Engineering: Embedded and Realtime Systems, Embedded Linux
Phone: (+49)-8142-66989-10 Fax: (+49)-8142-66989-80 Email: wd@denx.de
If you hear an onion ring, answer it.
^ permalink raw reply
* [PATCH] ppc32/ppc64: cleanup /proc/device-tree
From: Benjamin Herrenschmidt @ 2005-06-01 7:07 UTC (permalink / raw)
To: Andrew Morton; +Cc: linuxppc64-dev, Linus Torvalds, linuxppc-dev list
Hi !
This patch cleans up the /proc/device-tree representation of the Open
Firmware device-tree on ppc and ppc64. It does the following things:
- Workaround an issue in some Apple device-trees where a property may
exist with the same name as a child node of the parent. We now simply
"drop" the property instead of creating duplicate entries in /proc with
random result...
- Do not try to chop off the "@0" at the end of a node name whose unit
address is 0. This is not useful, inconsistent, and the code was buggy
and didn't always work anyway.
- Do not create symlinks for the short name and unit address parts of a
ndoe. These were never really used, bloated the memory footprint of the
device-tree with useless struct proc_dir_entry and their matching dentry
and inode cache bloat.
This results in smaller code, smaller memory footprint, and a more
accurate view of the tree presented to userland.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Index: linux-work/fs/proc/proc_devtree.c
===================================================================
--- linux-work.orig/fs/proc/proc_devtree.c 2005-06-01 16:18:51.000000000 +1000
+++ linux-work/fs/proc/proc_devtree.c 2005-06-01 16:47:35.000000000 +1000
@@ -12,15 +12,8 @@
#include <asm/uaccess.h>
#ifndef HAVE_ARCH_DEVTREE_FIXUPS
-static inline void set_node_proc_entry(struct device_node *np, struct proc_dir_entry *de)
-{
-}
-
-static void inline set_node_name_link(struct device_node *np, struct proc_dir_entry *de)
-{
-}
-
-static void inline set_node_addr_link(struct device_node *np, struct proc_dir_entry *de)
+static inline void set_node_proc_entry(struct device_node *np,
+ struct proc_dir_entry *de)
{
}
#endif
@@ -58,89 +51,67 @@
/*
* Process a node, adding entries for its children and its properties.
*/
-void proc_device_tree_add_node(struct device_node *np, struct proc_dir_entry *de)
+void proc_device_tree_add_node(struct device_node *np,
+ struct proc_dir_entry *de)
{
struct property *pp;
struct proc_dir_entry *ent;
- struct device_node *child, *sib;
- const char *p, *at;
- int l;
- struct proc_dir_entry *list, **lastp, *al;
+ struct device_node *child;
+ struct proc_dir_entry *list = NULL, **lastp;
+ const char *p;
set_node_proc_entry(np, de);
lastp = &list;
- for (pp = np->properties; pp != 0; pp = pp->next) {
- /*
- * Unfortunately proc_register puts each new entry
- * at the beginning of the list. So we rearrange them.
- */
- ent = create_proc_read_entry(pp->name, strncmp(pp->name, "security-", 9) ?
- S_IRUGO : S_IRUSR, de, property_read_proc, pp);
- if (ent == 0)
- break;
- if (!strncmp(pp->name, "security-", 9))
- ent->size = 0; /* don't leak number of password chars */
- else
- ent->size = pp->length;
- *lastp = ent;
- lastp = &ent->next;
- }
- child = NULL;
- while ((child = of_get_next_child(np, child))) {
+ for (child = NULL; (child = of_get_next_child(np, child));) {
p = strrchr(child->full_name, '/');
if (!p)
p = child->full_name;
else
++p;
- /* chop off '@0' if the name ends with that */
- l = strlen(p);
- if (l > 2 && p[l-2] == '@' && p[l-1] == '0')
- l -= 2;
ent = proc_mkdir(p, de);
if (ent == 0)
break;
*lastp = ent;
+ ent->next = NULL;
lastp = &ent->next;
proc_device_tree_add_node(child, ent);
-
- /*
- * If we left the address part on the name, consider
- * adding symlinks from the name and address parts.
- */
- if (p[l] != 0 || (at = strchr(p, '@')) == 0)
- continue;
-
+ }
+ of_node_put(child);
+ for (pp = np->properties; pp != 0; pp = pp->next) {
/*
- * If this is the first node with a given name property,
- * add a symlink with the name property as its name.
+ * Yet another Apple device-tree bogosity: on some machines,
+ * they have properties & nodes with the same name. Those
+ * properties are quite unimportant for us though, thus we
+ * simply "skip" them here, but we do have to check.
*/
- sib = NULL;
- while ((sib = of_get_next_child(np, sib)) && sib != child)
- if (sib->name && strcmp(sib->name, child->name) == 0)
- break;
- if (sib == child && strncmp(p, child->name, l) != 0) {
- al = proc_symlink(child->name, de, ent->name);
- if (al == 0) {
- of_node_put(sib);
+ for (ent = list; ent != NULL; ent = ent->next)
+ if (!strcmp(ent->name, pp->name))
break;
- }
- set_node_name_link(child, al);
- *lastp = al;
- lastp = &al->next;
+ if (ent != NULL) {
+ printk(KERN_WARNING "device-tree: property \"%s\" name"
+ " conflicts with node in %s\n", pp->name,
+ np->full_name);
+ continue;
}
- of_node_put(sib);
+
/*
- * Add another directory with the @address part as its name.
+ * Unfortunately proc_register puts each new entry
+ * at the beginning of the list. So we rearrange them.
*/
- al = proc_symlink(at, de, ent->name);
- if (al == 0)
+ ent = create_proc_read_entry(pp->name,
+ strncmp(pp->name, "security-", 9)
+ ? S_IRUGO : S_IRUSR, de,
+ property_read_proc, pp);
+ if (ent == 0)
break;
- set_node_addr_link(child, al);
- *lastp = al;
- lastp = &al->next;
+ if (!strncmp(pp->name, "security-", 9))
+ ent->size = 0; /* don't leak number of password chars */
+ else
+ ent->size = pp->length;
+ ent->next = NULL;
+ *lastp = ent;
+ lastp = &ent->next;
}
- of_node_put(child);
- *lastp = NULL;
de->subdir = list;
}
Index: linux-work/include/asm-ppc64/prom.h
===================================================================
--- linux-work.orig/include/asm-ppc64/prom.h 2005-06-01 16:18:51.000000000 +1000
+++ linux-work/include/asm-ppc64/prom.h 2005-06-01 16:30:30.000000000 +1000
@@ -147,9 +147,7 @@
struct device_node *sibling;
struct device_node *next; /* next device of same type */
struct device_node *allnext; /* next in list of all nodes */
- struct proc_dir_entry *pde; /* this node's proc directory */
- struct proc_dir_entry *name_link; /* name symlink */
- struct proc_dir_entry *addr_link; /* addr symlink */
+ struct proc_dir_entry *pde; /* this node's proc directory */
struct kref kref;
unsigned long _flags;
};
@@ -174,15 +172,6 @@
dn->pde = de;
}
-static void inline set_node_name_link(struct device_node *dn, struct proc_dir_entry *de)
-{
- dn->name_link = de;
-}
-
-static void inline set_node_addr_link(struct device_node *dn, struct proc_dir_entry *de)
-{
- dn->addr_link = de;
-}
/* OBSOLETE: Old stlye node lookup */
extern struct device_node *find_devices(const char *name);
Index: linux-work/arch/ppc64/kernel/pSeries_reconfig.c
===================================================================
--- linux-work.orig/arch/ppc64/kernel/pSeries_reconfig.c 2005-06-01 16:18:51.000000000 +1000
+++ linux-work/arch/ppc64/kernel/pSeries_reconfig.c 2005-06-01 16:30:30.000000000 +1000
@@ -47,14 +47,6 @@
remove_proc_entry(pp->name, np->pde);
pp = pp->next;
}
-
- /* Assuming that symlinks have the same parent directory as
- * np->pde.
- */
- if (np->name_link)
- remove_proc_entry(np->name_link->name, parent->pde);
- if (np->addr_link)
- remove_proc_entry(np->addr_link->name, parent->pde);
if (np->pde)
remove_proc_entry(np->pde->name, parent->pde);
}
^ permalink raw reply
* [PATCH] ppc32: Apple device-tree bug fix
From: Benjamin Herrenschmidt @ 2005-06-01 7:02 UTC (permalink / raw)
To: Andrew Morton; +Cc: linuxppc-dev list, Linus Torvalds
Hi !
This is the ppc32 patch equivalent to the just posted ppc64 one working
around a bug in Apple device-trees regarding the "cpus" nodes.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Index: linux-work/arch/ppc/syslib/prom_init.c
===================================================================
--- linux-work.orig/arch/ppc/syslib/prom_init.c 2005-05-02 10:48:08.000000000 +1000
+++ linux-work/arch/ppc/syslib/prom_init.c 2005-06-01 16:09:27.000000000 +1000
@@ -626,8 +626,18 @@
l = call_prom("package-to-path", 3, 1, node,
mem_start, mem_end - mem_start);
if (l >= 0) {
+ char *p, *ep;
+
np->full_name = PTRUNRELOC((char *) mem_start);
*(char *)(mem_start + l) = 0;
+ /* Fixup an Apple bug where they have bogus \0 chars in the
+ * middle of the path in some properties
+ */
+ for (p = (char *)mem_start, ep = p + l; p < ep; p++)
+ if ((*p) == '\0') {
+ memmove(p, p+1, ep - p);
+ ep--;
+ }
mem_start = ALIGNUL(mem_start + l + 1);
}
^ permalink raw reply
* Newbie question on Linux-PPC
From: Srivatsan CR @ 2005-06-01 5:38 UTC (permalink / raw)
To: linuxppc-embedded
[-- Attachment #1: Type: text/plain, Size: 617 bytes --]
Dear all,
I am having a MPC8260 based board with the following memory map.
Device Start address End address
EPROM 0x00000000 0x03FFFFFF
SDRAM 0x04000000 0x13FFFFFF
I have a doubt regarding Linux Port onto this board. I have read on the web
that Linux usually expects the SDRAM at 0x0, is it that the porting of linux
onto this board is totally impossible? If the porting is possible can anyone
help me out where to change the memory mapping of Linux for MPC8260?
Thanking you all for your time. Kindly help me out to solve this issue.
With Regards,
C.R.Srivatsan
[-- Attachment #2: Type: text/html, Size: 8057 bytes --]
^ permalink raw reply
* Re: Dynamic libraries do not work
From: Theo Gjaltema @ 2005-05-31 20:29 UTC (permalink / raw)
To: linuxppc-embedded
In-Reply-To: <E6CEFEB5-1F03-45DA-8BA3-C1F1511950EA@aimsys.nl>
I 've found the problem, the ramdisk used contained executables as well
as dyn. libs from the mpc8260 instead of the mpc862.
I don't know why the whole system came to a halt without any message but
replacing the dyn. libs and executables with the correct ones solved the
problem of crashing.
Many thanks for your responses,
Theo.
Jaap-Jan Boor schreef:
> Theo,
>
> What type of processor are you using? 8xx?
> Did you build a tool-chain yourself and are
> you perhaps using floating point?
>
> Jaap-Jan
>
> On 26-mei-2005, at 23:04, Theo Gjaltema wrote:
>
>> Hello,
>>
>> I have a linux 2.4.20 kernel running, but the files in the ramdisk
>> fail to execute if they are dynamically build.
>> The whole system stops (debuggers shows that it crashed while in an
>> erea where no flash/ram is present.
>> Anyone an idea?
>> There is nog difference between the use of a ramdisk or an nfs
>> mounted root filesystem.
>>
>> Greetings,
>> Theo.
>>
>>
>> _______________________________________________
>> Linuxppc-embedded mailing list
>> Linuxppc-embedded@ozlabs.org
>> https://ozlabs.org/mailman/listinfo/linuxppc-embedded
>>
>
> ____
> J.G.J. Boor Anton Philipsweg 1
> Software Engineer 1223 KZ Hilversum
> AimSys bv tel. +31 35 689 1941
> Postbus 2194, 1200 CD Hilversum jjboor at aimsys dot nl
>
>
>
^ permalink raw reply
* Re: RFC: PHY Abstraction Layer II
From: Stephen Hemminger @ 2005-05-31 17:59 UTC (permalink / raw)
To: Andy Fleming; +Cc: Netdev, Embedded PPC Linux list
In-Reply-To: <1107b64b01fb8e9a6c84359bb56881a6@freescale.com>
Here are some patches:
* allow phy's to be modules
* use driver owner for ref count
* make local functions static where ever possible
* get rid of bus read may sleep implication in comment.
since you are holding phy spin lock it better not!!
Untested since I don't have sungem, but am thinking about this for skge
driver.
Index: skge-phy/drivers/net/phy/davicom.c
===================================================================
--- skge-phy.orig/drivers/net/phy/davicom.c
+++ skge-phy/drivers/net/phy/davicom.c
@@ -60,13 +60,17 @@
#define MII_DM9161_10BTCSR 0x12
#define MII_DM9161_10BTCSR_INIT 0x7800
+MODULE_DESCRIPTION("Davicom PHY driver");
+MODULE_AUTHOR("Andy Fleming");
+MODULE_LICENSE("GPL");
+
struct dm9161_private {
struct timer_list timer;
int resetdone;
};
#define DM9161_DELAY 1
-int dm9161_config_intr(struct phy_device *phydev)
+static int dm9161_config_intr(struct phy_device *phydev)
{
int temp;
@@ -226,6 +230,7 @@ static struct phy_driver dm9161_driver =
.config_aneg = dm9161_config_aneg,
.read_status = genphy_read_status,
.remove = dm9161_remove,
+ .driver = { .owner = THIS_MODULE,},
};
static struct phy_driver dm9131_driver = {
@@ -238,38 +243,33 @@ static struct phy_driver dm9131_driver =
.read_status = genphy_read_status,
.ack_interrupt = dm9161_ack_interrupt,
.config_intr = dm9161_config_intr,
+ .driver = { .owner = THIS_MODULE,},
};
-int __init dm9161_init(void)
+static int __init davicom_init(void)
{
- int retval;
+ int ret;
- retval = phy_driver_register(&dm9161_driver);
+ ret = phy_driver_register(&dm9161_driver);
+ if (ret)
+ goto err1;
- return retval;
-}
+ ret = phy_driver_register(&dm9131_driver);
+ if (ret)
+ goto err2;
+ return 0;
-static void __exit dm9161_exit(void)
-{
+ err2:
phy_driver_unregister(&dm9161_driver);
+ err1:
+ return ret;
}
-module_init(dm9161_init);
-module_exit(dm9161_exit);
-
-int __init dm9131_init(void)
-{
- int retval;
-
- retval = phy_driver_register(&dm9131_driver);
-
- return retval;
-}
-
-static void __exit dm9131_exit(void)
+static void __exit davicom_exit(void)
{
+ phy_driver_unregister(&dm9161_driver);
phy_driver_unregister(&dm9131_driver);
}
-module_init(dm9131_init);
-module_exit(dm9131_exit);
+module_init(davicom_init);
+module_exit(davicom_exit);
Index: skge-phy/drivers/net/phy/marvell.c
===================================================================
--- skge-phy.orig/drivers/net/phy/marvell.c
+++ skge-phy/drivers/net/phy/marvell.c
@@ -45,6 +45,10 @@
#define MII_M1011_IMASK_INIT 0x6400
#define MII_M1011_IMASK_CLEAR 0x0000
+MODULE_DESCRIPTION("Marvell PHY driver");
+MODULE_AUTHOR("Andy Fleming");
+MODULE_LICENSE("GPL");
+
static int marvell_ack_interrupt(struct phy_device *phydev)
{
int err;
@@ -119,15 +123,12 @@ static struct phy_driver m88e1101_driver
.read_status = &genphy_read_status,
.ack_interrupt = &marvell_ack_interrupt,
.config_intr = &marvell_config_intr,
+ .driver = { .owner = THIS_MODULE,},
};
-int __init marvell_init(void)
+static int __init marvell_init(void)
{
- int retval;
-
- retval = phy_driver_register(&m88e1101_driver);
-
- return retval;
+ return phy_driver_register(&m88e1101_driver);
}
static void __exit marvell_exit(void)
Index: skge-phy/drivers/net/phy/lxt.c
===================================================================
--- skge-phy.orig/drivers/net/phy/lxt.c
+++ skge-phy/drivers/net/phy/lxt.c
@@ -58,6 +58,10 @@
#define MII_LXT971_ISR 19 /* Interrupt Status Register */
+MODULE_DESCRIPTION("Intel LXT PHY driver");
+MODULE_AUTHOR("Andy Fleming");
+MODULE_LICENSE("GPL");
+
static int lxt970_ack_interrupt(struct phy_device *phydev)
{
int err;
@@ -130,6 +134,7 @@ static struct phy_driver lxt970_driver =
.read_status = genphy_read_status,
.ack_interrupt = lxt970_ack_interrupt,
.config_intr = lxt970_config_intr,
+ .driver = { .owner = THIS_MODULE,},
};
static struct phy_driver lxt971_driver = {
@@ -142,38 +147,33 @@ static struct phy_driver lxt971_driver =
.read_status = genphy_read_status,
.ack_interrupt = lxt971_ack_interrupt,
.config_intr = lxt971_config_intr,
+ .driver = { .owner = THIS_MODULE,},
};
-int __init lxt970_init(void)
+static int __init lxt_init(void)
{
- int retval;
+ int ret;
- retval = phy_driver_register(&lxt970_driver);
+ ret = phy_driver_register(&lxt970_driver);
+ if (ret)
+ goto err1;
- return retval;
-}
+ ret = phy_driver_register(&lxt971_driver);
+ if (ret)
+ goto err2;
+ return 0;
-static void __exit lxt970_exit(void)
-{
+ err2:
phy_driver_unregister(&lxt970_driver);
+ err1:
+ return ret;
}
-module_init(lxt970_init);
-module_exit(lxt970_exit);
-
-int __init lxt971_init(void)
-{
- int retval;
-
- retval = phy_driver_register(&lxt971_driver);
-
- return retval;
-}
-
-static void __exit lxt971_exit(void)
+static void __exit lxt_exit(void)
{
+ phy_driver_unregister(&lxt970_driver);
phy_driver_unregister(&lxt971_driver);
}
-module_init(lxt971_init);
-module_exit(lxt971_exit);
+module_init(lxt_init);
+module_exit(lxt_exit);
Index: skge-phy/drivers/net/phy/qsemi.c
===================================================================
--- skge-phy.orig/drivers/net/phy/qsemi.c
+++ skge-phy/drivers/net/phy/qsemi.c
@@ -59,9 +59,12 @@
#define QS6612_PCR_MLT3_DIS 0x0002
#define QS6612_PCR_SCRM_DESCRM 0x0001
+MODULE_DESCRIPTION("Quality Semiconductor PHY driver");
+MODULE_AUTHOR("Andy Fleming");
+MODULE_LICENSE("GPL");
/* Returns 0, unless there's a write error */
-int qs6612_probe(struct phy_device *phydev)
+static int qs6612_probe(struct phy_device *phydev)
{
/* The PHY powers up isolated on the RPX,
* so send a command to allow operation.
@@ -77,7 +80,7 @@ int qs6612_probe(struct phy_device *phyd
return phy_write(phydev, MII_QS6612_PCR, 0x0dc0);
}
-int qs6612_ack_interrupt(struct phy_device *phydev)
+static int qs6612_ack_interrupt(struct phy_device *phydev)
{
int err;
@@ -99,7 +102,7 @@ int qs6612_ack_interrupt(struct phy_devi
return 0;
}
-int qs6612_config_intr(struct phy_device *phydev)
+static int qs6612_config_intr(struct phy_device *phydev)
{
int err;
if (phydev->interrupts == PHY_INTERRUPT_ENABLED)
@@ -123,15 +126,12 @@ static struct phy_driver qs6612_driver =
.read_status = genphy_read_status,
.ack_interrupt = qs6612_ack_interrupt,
.config_intr = qs6612_config_intr,
+ .driver = { .owner = THIS_MODULE,},
};
-int __init qs6612_init(void)
+static int __init qs6612_init(void)
{
- int retval;
-
- retval = phy_driver_register(&qs6612_driver);
-
- return retval;
+ return phy_driver_register(&qs6612_driver);
}
static void __exit qs6612_exit(void)
Index: skge-phy/drivers/net/phy/phy_device.c
===================================================================
--- skge-phy.orig/drivers/net/phy/phy_device.c
+++ skge-phy/drivers/net/phy/phy_device.c
@@ -370,7 +370,7 @@ int genphy_config_advert(struct phy_devi
return adv;
}
-
+EXPORT_SYMBOL(genphy_config_advert);
/* genphy_setup_forced
*
@@ -443,7 +443,7 @@ int genphy_config_aneg(struct phy_device
return err;
}
-
+EXPORT_SYMBOL(genphy_config_aneg);
/* genphy_update_link
*
@@ -567,7 +567,7 @@ int genphy_read_status(struct phy_device
return 0;
}
-
+EXPORT_SYMBOL(genphy_read_status);
static int genphy_probe(struct phy_device *phydev)
{
@@ -624,7 +624,7 @@ static int genphy_probe(struct phy_devic
* set the state to READY (the driver's probe function should
* set it to STARTING if needed).
*/
-int phy_probe(struct device *dev)
+static int phy_probe(struct device *dev)
{
struct phy_device *phydev;
struct phy_driver *phydrv;
@@ -662,7 +662,7 @@ int phy_probe(struct device *dev)
return err;
}
-int phy_remove(struct device *dev)
+static int phy_remove(struct device *dev)
{
struct phy_device *phydev;
@@ -701,13 +701,15 @@ int phy_driver_register(struct phy_drive
return retval;
}
+EXPORT_SYMBOL(phy_driver_register);
void phy_driver_unregister(struct phy_driver *drv)
{
driver_unregister(&drv->driver);
}
+EXPORT_SYMBOL(phy_driver_unregister);
-struct phy_driver genphy_driver = {
+static struct phy_driver genphy_driver = {
.phy_id = 0xffffffff,
.phy_id_mask = 0xffffffff,
.name = "Generic PHY",
@@ -715,15 +717,13 @@ struct phy_driver genphy_driver = {
.features = 0,
.config_aneg = genphy_config_aneg,
.read_status = genphy_read_status,
+ .driver = {.owner = THIS_MODULE, },
};
static int __init genphy_init(void)
{
- int retval;
-
- retval = phy_driver_register(&genphy_driver);
+ return phy_driver_register(&genphy_driver);
- return retval;
}
static void __exit genphy_exit(void)
Index: skge-phy/drivers/net/phy/mdio_bus.c
===================================================================
--- skge-phy.orig/drivers/net/phy/mdio_bus.c
+++ skge-phy/drivers/net/phy/mdio_bus.c
@@ -124,7 +124,7 @@ EXPORT_SYMBOL(unregister_mdiobus);
* description: Given a PHY device, and a PHY driver, return 1 if
* the driver supports the device. Otherwise, return 0
*/
-int mdio_bus_match(struct device *dev, struct device_driver *drv)
+static int mdio_bus_match(struct device *dev, struct device_driver *drv)
{
struct phy_device *phydev = to_phy_device(dev);
struct phy_driver *phydrv = to_phy_driver(drv);
@@ -170,7 +170,7 @@ struct bus_type mdio_bus_type = {
.resume = mdio_bus_resume,
};
-int __init mdio_bus_init(void)
+static int __init mdio_bus_init(void)
{
return bus_register(&mdio_bus_type);
}
Index: skge-phy/drivers/net/phy/cicada.c
===================================================================
--- skge-phy.orig/drivers/net/phy/cicada.c
+++ skge-phy/drivers/net/phy/cicada.c
@@ -65,6 +65,9 @@
#define MII_CIS8201_AUXCONSTAT_GBIT 0x0010
#define MII_CIS8201_AUXCONSTAT_100 0x0008
+MODULE_DESCRIPTION("Cicadia PHY driver");
+MODULE_AUTHOR("Andy Fleming");
+MODULE_LICENSE("GPL");
static int cis820x_probe(struct phy_device *phydev)
{
@@ -104,9 +107,9 @@ static int cis820x_config_intr(struct ph
/* Cicada 820x */
static struct phy_driver cis8204_driver = {
- 0x000fc440,
- "Cicada Cis8204",
- 0x000fffc0,
+ .phy_id = 0x000fc440,
+ .name = "Cicada Cis8204",
+ .phy_id_mask = 0x000fffc0,
.features = PHY_GBIT_FEATURES,
.flags = PHY_HAS_INTERRUPT,
.probe = &cis820x_probe,
@@ -114,15 +117,12 @@ static struct phy_driver cis8204_driver
.read_status = &genphy_read_status,
.ack_interrupt = &cis820x_ack_interrupt,
.config_intr = &cis820x_config_intr,
+ .driver = { .owner = THIS_MODULE,},
};
-int __init cis8204_init(void)
+static int __init cis8204_init(void)
{
- int retval;
-
- retval = phy_driver_register(&cis8204_driver);
-
- return retval;
+ return phy_driver_register(&cis8204_driver);
}
static void __exit cis8204_exit(void)
Index: skge-phy/drivers/net/phy/phy.c
===================================================================
--- skge-phy.orig/drivers/net/phy/phy.c
+++ skge-phy/drivers/net/phy/phy.c
@@ -42,10 +42,7 @@
int phy_read(struct phy_device *phydev, u16 regnum);
int phy_write(struct phy_device *phydev, u16 regnum, u16 val);
-/* Convenience functions for reading a given PHY register.
- * This MUST NOT be called from interrupt context,
- * because the bus read function may sleep
- * or generally lock up. */
+/* Convenience functions for reading a given PHY register. */
int phy_read(struct phy_device *phydev, u16 regnum)
{
int retval;
@@ -57,6 +54,7 @@ int phy_read(struct phy_device *phydev,
return retval;
}
+EXPORT_SYMBOL(phy_read);
int phy_write(struct phy_device *phydev, u16 regnum, u16 val)
{
@@ -69,6 +67,7 @@ int phy_write(struct phy_device *phydev,
return err;
}
+EXPORT_SYMBOL(phy_write);
int phy_clear_interrupt(struct phy_device *phydev)
@@ -236,7 +235,7 @@ static inline int phy_find_valid(int idx
* duplexes. Drop down by one in this order: 1000/FULL,
* 1000/HALF, 100/FULL, 100/HALF, 10/FULL, 10/HALF
*/
-void phy_sanitize_settings(struct phy_device *phydev)
+static void phy_sanitize_settings(struct phy_device *phydev)
{
u32 features = phydev->supported;
int idx;
@@ -260,7 +259,7 @@ void phy_sanitize_settings(struct phy_de
* 1000/FULL, 1000/HALF, 100/FULL, 100/HALF,
* 10/FULL, 10/HALF. The function bottoms out at 10/HALF.
*/
-void phy_force_reduction(struct phy_device *phydev)
+static void phy_force_reduction(struct phy_device *phydev)
{
int idx;
@@ -323,7 +322,7 @@ static irqreturn_t phy_interrupt(int irq
* Otherwise, we enable the interrupts in the PHY.
* Returns 0 on success.
*/
-int phy_start_interrupts(struct phy_device *phydev)
+static int phy_start_interrupts(struct phy_device *phydev)
{
int err = 0;
^ permalink raw reply
* Re: Complete ccsr map for mpc8540 available?
From: Clemens Koller @ 2005-05-31 16:17 UTC (permalink / raw)
To: Kumar Gala; +Cc: linuxppc-embedded
In-Reply-To: <bb83727d8d949477f261e00351c091f2@freescale.com>
Hello, Kumar!
> > [...]
> Yes, that was my thinking. You can grab just the lbc bits and put them
> in immap_85xx.h and do the same ioremap thing we do for pci in
> arch/ppc/syslib/ppc85xx_setup.c.
Yes, ioremap() and ioremap_nocache() works fine.
I just try to get the maximum speed out of the Local Bus Mapped dual port
SRAM in our FPGA.
>> I can release my stuff, if anybody is interested... no problem.
>> The LBC part is verified (some others are dummys and untested) and in
>> a /works for me/ state.
>
> It sounds like this is custom to your board so I wouldn't bother
> releasing it out unless it something you want to get into the standard
> kernel tree.
Well, the immr is good for every mpc8540 and the other friends you know.
(more than me)
Greets,
Clemens Koller
_______________________________
R&D Imaging Devices
Anagramm GmbH
Rupert-Mayer-Str. 45/1
81379 Muenchen
Germany
http://www.anagramm.de
Phone: +49-89-741518-50
Fax: +49-89-741518-19
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox