* Re: Not show login correct
From: Wolfgang Denk @ 2006-11-03 16:45 UTC (permalink / raw)
To: tran vanle; +Cc: linuxppc-embedded
In-Reply-To: <20061103142757.35508.qmail@web33012.mail.mud.yahoo.com>
In message <20061103142757.35508.qmail@web33012.mail.mud.yahoo.com> you wrote:
>
> I have just build kernel and ramdisk for TQM8xxL success. But when I login I receive
> [root@h W] , my hostname is van and current directory is /root/bin ,May I receive [root@van bin]
..
> PS1="[$USER@\h \W]\\$ "
Check if your shell really supports such escape sequences. I guess
you might be running something different than bash which does not
understand this.
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 fail to plan, plan to fail.
^ permalink raw reply
* [PATCH 2.6.19-rc4 1/3] ehea: Nullpointer dereferencation fix
From: Thomas Klein @ 2006-11-03 16:47 UTC (permalink / raw)
To: Jeff Garzik
Cc: Thomas Klein, Jan-Bernd Themann, netdev, linux-kernel,
Christoph Raisch, linux-ppc, Marcus Eder
Fix: Must check for nullpointer before dereferencing it - not afterwards.
Signed-off-by: Thomas Klein <tklein@de.ibm.com>
---
diff -Nurp git.netdev-2.6.base/drivers/net/ehea/ehea_qmr.c git.netdev-2.6/drivers/net/ehea/ehea_qmr.c
--- git.netdev-2.6.base/drivers/net/ehea/ehea_qmr.c 2006-11-03 14:19:51.000000000 +0100
+++ git.netdev-2.6/drivers/net/ehea/ehea_qmr.c 2006-11-03 14:27:53.000000000 +0100
@@ -209,11 +209,11 @@ int ehea_destroy_cq(struct ehea_cq *cq)
{
u64 adapter_handle, hret;
- adapter_handle = cq->adapter->handle;
-
if (!cq)
return 0;
+ adapter_handle = cq->adapter->handle;
+
/* deregister all previous registered pages */
hret = ehea_h_free_resource(adapter_handle, cq->fw_handle);
if (hret != H_SUCCESS) {
^ permalink raw reply
* [PATCH 2.6.19-rc4 2/3] ehea: Removed redundant define
From: Thomas Klein @ 2006-11-03 16:47 UTC (permalink / raw)
To: Jeff Garzik
Cc: Thomas Klein, Jan-Bernd Themann, netdev, linux-kernel,
Christoph Raisch, linux-ppc, Marcus Eder
Removed define H_CB_ALIGNMENT which is already defined in include/asm-powerpc/hvcall.h
Signed-off-by: Thomas Klein <tklein@de.ibm.com>
---
diff -Nurp git.netdev-2.6.base/drivers/net/ehea/ehea.h git.netdev-2.6/drivers/net/ehea/ehea.h
--- git.netdev-2.6.base/drivers/net/ehea/ehea.h 2006-11-03 14:19:51.000000000 +0100
+++ git.netdev-2.6/drivers/net/ehea/ehea.h 2006-11-03 14:37:30.000000000 +0100
@@ -39,7 +39,7 @@
#include <asm/io.h>
#define DRV_NAME "ehea"
-#define DRV_VERSION "EHEA_0034"
+#define DRV_VERSION "EHEA_0043"
#define EHEA_MSG_DEFAULT (NETIF_MSG_LINK | NETIF_MSG_TIMER \
| NETIF_MSG_RX_ERR | NETIF_MSG_TX_ERR)
@@ -105,9 +105,6 @@
#define EHEA_BCMC_VLANID_ALL 0x01
#define EHEA_BCMC_VLANID_SINGLE 0x00
-/* Use this define to kmallocate pHYP control blocks */
-#define H_CB_ALIGNMENT 4096
-
#define EHEA_CACHE_LINE 128
/* Memory Regions */
^ permalink raw reply
* [PATCH 2.6.19-rc4 3/3] ehea: 64K page support fix
From: Thomas Klein @ 2006-11-03 16:48 UTC (permalink / raw)
To: Jeff Garzik
Cc: Thomas Klein, Jan-Bernd Themann, netdev, linux-kernel,
Christoph Raisch, linux-ppc, Marcus Eder
This patch fixes 64k page support by using PAGE_MASK and appropriate pagesize defines in several places.
Signed-off-by: Thomas Klein <tklein@de.ibm.com>
----
drivers/net/ehea/ehea_ethtool.c | 2 +-
drivers/net/ehea/ehea_main.c | 26 +++++++++++++-------------
drivers/net/ehea/ehea_phyp.c | 2 +-
drivers/net/ehea/ehea_phyp.h | 6 ++++--
drivers/net/ehea/ehea_qmr.c | 13 +++++++------
5 files changed, 26 insertions(+), 23 deletions(-)
diff -Nurp git.linux-2.6.base/drivers/net/ehea/ehea_ethtool.c git.linux-2.6/drivers/net/ehea/ehea_ethtool.c
--- git.linux-2.6.base/drivers/net/ehea/ehea_ethtool.c 2006-11-03 16:41:36.000000000 +0100
+++ git.linux-2.6/drivers/net/ehea/ehea_ethtool.c 2006-11-03 12:43:16.000000000 +0100
@@ -238,7 +238,7 @@ static void ehea_get_ethtool_stats(struc
data[i++] = port->port_res[0].swqe_refill_th;
data[i++] = port->resets;
- cb6 = kzalloc(H_CB_ALIGNMENT, GFP_KERNEL);
+ cb6 = kzalloc(PAGE_SIZE, GFP_KERNEL);
if (!cb6) {
ehea_error("no mem for cb6");
return;
diff -Nurp git.linux-2.6.base/drivers/net/ehea/ehea_main.c git.linux-2.6/drivers/net/ehea/ehea_main.c
--- git.linux-2.6.base/drivers/net/ehea/ehea_main.c 2006-11-03 16:41:36.000000000 +0100
+++ git.linux-2.6/drivers/net/ehea/ehea_main.c 2006-11-03 12:43:16.000000000 +0100
@@ -92,7 +92,7 @@ static struct net_device_stats *ehea_get
memset(stats, 0, sizeof(*stats));
- cb2 = kzalloc(H_CB_ALIGNMENT, GFP_KERNEL);
+ cb2 = kzalloc(PAGE_SIZE, GFP_KERNEL);
if (!cb2) {
ehea_error("no mem for cb2");
goto out;
@@ -586,8 +586,8 @@ int ehea_sense_port_attr(struct ehea_por
u64 hret;
struct hcp_ehea_port_cb0 *cb0;
- cb0 = kzalloc(H_CB_ALIGNMENT, GFP_ATOMIC); /* May be called via */
- if (!cb0) { /* ehea_neq_tasklet() */
+ cb0 = kzalloc(PAGE_SIZE, GFP_ATOMIC); /* May be called via */
+ if (!cb0) { /* ehea_neq_tasklet() */
ehea_error("no mem for cb0");
ret = -ENOMEM;
goto out;
@@ -670,7 +670,7 @@ int ehea_set_portspeed(struct ehea_port
u64 hret;
int ret = 0;
- cb4 = kzalloc(H_CB_ALIGNMENT, GFP_KERNEL);
+ cb4 = kzalloc(PAGE_SIZE, GFP_KERNEL);
if (!cb4) {
ehea_error("no mem for cb4");
ret = -ENOMEM;
@@ -985,7 +985,7 @@ static int ehea_configure_port(struct eh
struct hcp_ehea_port_cb0 *cb0;
ret = -ENOMEM;
- cb0 = kzalloc(H_CB_ALIGNMENT, GFP_KERNEL);
+ cb0 = kzalloc(PAGE_SIZE, GFP_KERNEL);
if (!cb0)
goto out;
@@ -1443,7 +1443,7 @@ static int ehea_set_mac_addr(struct net_
goto out;
}
- cb0 = kzalloc(H_CB_ALIGNMENT, GFP_KERNEL);
+ cb0 = kzalloc(PAGE_SIZE, GFP_KERNEL);
if (!cb0) {
ehea_error("no mem for cb0");
ret = -ENOMEM;
@@ -1501,7 +1501,7 @@ static void ehea_promiscuous(struct net_
if ((enable && port->promisc) || (!enable && !port->promisc))
return;
- cb7 = kzalloc(H_CB_ALIGNMENT, GFP_ATOMIC);
+ cb7 = kzalloc(PAGE_SIZE, GFP_ATOMIC);
if (!cb7) {
ehea_error("no mem for cb7");
goto out;
@@ -1870,7 +1870,7 @@ static void ehea_vlan_rx_register(struct
port->vgrp = grp;
- cb1 = kzalloc(H_CB_ALIGNMENT, GFP_KERNEL);
+ cb1 = kzalloc(PAGE_SIZE, GFP_KERNEL);
if (!cb1) {
ehea_error("no mem for cb1");
goto out;
@@ -1899,7 +1899,7 @@ static void ehea_vlan_rx_add_vid(struct
int index;
u64 hret;
- cb1 = kzalloc(H_CB_ALIGNMENT, GFP_KERNEL);
+ cb1 = kzalloc(PAGE_SIZE, GFP_KERNEL);
if (!cb1) {
ehea_error("no mem for cb1");
goto out;
@@ -1935,7 +1935,7 @@ static void ehea_vlan_rx_kill_vid(struct
if (port->vgrp)
port->vgrp->vlan_devices[vid] = NULL;
- cb1 = kzalloc(H_CB_ALIGNMENT, GFP_KERNEL);
+ cb1 = kzalloc(PAGE_SIZE, GFP_KERNEL);
if (!cb1) {
ehea_error("no mem for cb1");
goto out;
@@ -1968,7 +1968,7 @@ int ehea_activate_qp(struct ehea_adapter
u64 dummy64 = 0;
struct hcp_modify_qp_cb0* cb0;
- cb0 = kzalloc(H_CB_ALIGNMENT, GFP_KERNEL);
+ cb0 = kzalloc(PAGE_SIZE, GFP_KERNEL);
if (!cb0) {
ret = -ENOMEM;
goto out;
@@ -2269,7 +2269,7 @@ int ehea_sense_adapter_attr(struct ehea_
u64 hret;
int ret;
- cb = kzalloc(H_CB_ALIGNMENT, GFP_KERNEL);
+ cb = kzalloc(PAGE_SIZE, GFP_KERNEL);
if (!cb) {
ret = -ENOMEM;
goto out;
@@ -2340,7 +2340,7 @@ static int ehea_setup_single_port(struct
goto out;
/* Enable Jumbo frames */
- cb4 = kzalloc(H_CB_ALIGNMENT, GFP_KERNEL);
+ cb4 = kzalloc(PAGE_SIZE, GFP_KERNEL);
if (!cb4) {
ehea_error("no mem for cb4");
} else {
diff -Nurp git.linux-2.6.base/drivers/net/ehea/ehea_phyp.c git.linux-2.6/drivers/net/ehea/ehea_phyp.c
--- git.linux-2.6.base/drivers/net/ehea/ehea_phyp.c 2006-11-03 16:41:36.000000000 +0100
+++ git.linux-2.6/drivers/net/ehea/ehea_phyp.c 2006-11-03 12:43:16.000000000 +0100
@@ -506,7 +506,7 @@ u64 ehea_h_register_rpage_mr(const u64 a
const u8 pagesize, const u8 queue_type,
const u64 log_pageaddr, const u64 count)
{
- if ((count > 1) && (log_pageaddr & 0xfff)) {
+ if ((count > 1) && (log_pageaddr & ~PAGE_MASK)) {
ehea_error("not on pageboundary");
return H_PARAMETER;
}
diff -Nurp git.linux-2.6.base/drivers/net/ehea/ehea_phyp.h git.linux-2.6/drivers/net/ehea/ehea_phyp.h
--- git.linux-2.6.base/drivers/net/ehea/ehea_phyp.h 2006-11-03 16:41:36.000000000 +0100
+++ git.linux-2.6/drivers/net/ehea/ehea_phyp.h 2006-11-03 12:43:16.000000000 +0100
@@ -81,14 +81,16 @@ static inline u32 get_longbusy_msecs(int
static inline void hcp_epas_ctor(struct h_epas *epas, u64 paddr_kernel,
u64 paddr_user)
{
- epas->kernel.addr = ioremap(paddr_kernel, PAGE_SIZE);
+ /* To support 64k pages we must round to 64k page boundary */
+ epas->kernel.addr = ioremap((paddr_kernel & PAGE_MASK), PAGE_SIZE) +
+ (paddr_kernel & ~PAGE_MASK);
epas->user.addr = paddr_user;
}
static inline void hcp_epas_dtor(struct h_epas *epas)
{
if (epas->kernel.addr)
- iounmap(epas->kernel.addr);
+ iounmap((void __iomem*)((u64)epas->kernel.addr & PAGE_MASK));
epas->user.addr = 0;
epas->kernel.addr = 0;
diff -Nurp git.linux-2.6.base/drivers/net/ehea/ehea_qmr.c git.linux-2.6/drivers/net/ehea/ehea_qmr.c
--- git.linux-2.6.base/drivers/net/ehea/ehea_qmr.c 2006-11-03 17:04:11.000000000 +0100
+++ git.linux-2.6/drivers/net/ehea/ehea_qmr.c 2006-11-03 12:43:16.000000000 +0100
@@ -512,7 +512,7 @@ int ehea_reg_mr_adapter(struct ehea_adap
start = KERNELBASE;
end = (u64)high_memory;
- nr_pages = (end - start) / PAGE_SIZE;
+ nr_pages = (end - start) / EHEA_PAGESIZE;
pt = kzalloc(PAGE_SIZE, GFP_KERNEL);
if (!pt) {
@@ -538,9 +538,9 @@ int ehea_reg_mr_adapter(struct ehea_adap
if (nr_pages > 1) {
u64 num_pages = min(nr_pages, (u64)512);
for (i = 0; i < num_pages; i++)
- pt[i] = virt_to_abs((void*)(((u64)start)
- + ((k++) *
- PAGE_SIZE)));
+ pt[i] = virt_to_abs((void*)(((u64)start) +
+ ((k++) *
+ EHEA_PAGESIZE)));
hret = ehea_h_register_rpage_mr(adapter->handle,
adapter->mr.handle, 0,
@@ -548,8 +548,9 @@ int ehea_reg_mr_adapter(struct ehea_adap
num_pages);
nr_pages -= num_pages;
} else {
- u64 abs_adr = virt_to_abs((void*)(((u64)start)
- + (k * PAGE_SIZE)));
+ u64 abs_adr = virt_to_abs((void*)(((u64)start) +
+ (k * EHEA_PAGESIZE)));
+
hret = ehea_h_register_rpage_mr(adapter->handle,
adapter->mr.handle, 0,
0, abs_adr,1);
^ permalink raw reply
* Re: Clear OS / HAL separation
From: Grant Likely @ 2006-11-03 17:47 UTC (permalink / raw)
To: M Ptich; +Cc: linuxppc-dev list
In-Reply-To: <BAY102-F362BE9713459EAE9EED9FAA9FE0@phx.gbl>
On 11/3/06, M Ptich <ptich@hotmail.com> wrote:
> Hi Grant,
>
> Thanks a lot for your kind reply. What I meant is inordinate amount of
> sometimes ifdefs, sometimes call redirection (like ppc_md), pretty messy.
> But it is mostly in already machine-dependent code, so does not count as bad
> separation, you're right.
>
> But I am wondering about your remark that "there is separation between
> bootloader and
> kernel responsibilities". I think that on PPC Kernel depends very little on
> the bootloader - bootloader just needs to set up 5 input parameters (one of
> them is a pointer to initialized bd_t), and have initial Kernel TLB with
> IPROT=1. That's it, all the devices (including internal CPU stuff) are
> initialized in the Kernel. Am I correct ?
If you're looking in arch/ppc, you are 100% correct. If you are
looking in arch/powerpc, which is where new development is occuring, a
device tree is used to pass information about available devices to the
kernel. Also, your boot loader *should* (but you don't need to do it
this way) setup your SOC configuration (gpio, etc). By doing it this
way, the device tree can encapsulate most of the differences between
different boards using the same processor (or SOC). Board specific
code is kept to a minimum; or in some cases is non-existent.
Everything you need can be covered by device drivers and processor
specific code.
However, unless you've got real openfirmware, it is still just a
handoff from the bootloader to the kernel. Once the kernel is booted,
it won't make any calls back to the bootloader.
Cheers,
g.
BTW, please make sure you include the mailing list when replying
--
Grant Likely, B.Sc. P.Eng.
Secret Lab Technologies Ltd.
grant.likely@secretlab.ca
(403) 399-0195
^ permalink raw reply
* Re: [patch 13/16] powerpc: make prom_init.o dependent on PPC_OF
From: Benjamin Herrenschmidt @ 2006-11-03 20:34 UTC (permalink / raw)
To: Sascha Hauer; +Cc: linuxppc-dev
In-Reply-To: <20061103094745.GE22478@localhost.localdomain>
> I don't know yet where the exact boarders are in the code between real
> OF and flat device tree. Maybe I can look at it once I have a proper
> device tree for my board.
> Out of curiosity I just disabled CONFIG_PPC_OF. There were two undefined
> references to functions I didn't need at the moment. After commenting
> them out the kernel compiled and booted. It saved me ~10k kernelsize,
> but ok, I thought I would still have flat tree support.
Hrm... it's unclear, I think we changed it a couple of times. In fact,
since the flat DT support is mandatory, I suppose CONFIG_PPC_OF could be
used as "supports booting from a real OF". But in this case, prom_init
is really the only thing that should be covered by it.
Right now, it's used for bits in pci_32.c which should always be enabled
for arch/powerpc so ...
Also, I think we could safely get rid of the pci_OF_bus_map. I don't
think it's ever been used and we have the devspec files now.
Ben.
^ permalink raw reply
* Re: Fw: [patch 08/16] powerpc: remove EMBEDDED6xx Kconfig entry
From: Benjamin Herrenschmidt @ 2006-11-03 20:46 UTC (permalink / raw)
To: Stephen Winiecki; +Cc: linuxppc-dev, paulus
In-Reply-To: <OFCD6BEB84.DE407CA1-ON8725721B.00508624-8525721B.00552A5F@us.ibm.com>
> OK - so in this sense PPC_MULTIPLATFORM would be used more to help
> categorize (make ppc platforms depend on it in Kconfig) as opposed to
> enabling different code/function? (thus some of Sascha's patches
> getting rid of CONFIG_PPC_MMULTIPLATFORM ifdefs)
I'd rather get rid of it completely.
> I should have more properly said "the majority of the existing
> 'embedded' platforms (not PSERIES, CHRP, PREP etc.) currently
> implmented in /power seem to define CONFIG_DEFAULT_UIMAGE"
Yes. Though I hope we'll see some alternatives to uboot soon
/me looks towards ojn and segher....
> Makes sense. Specific to the current wrapper though - the boot
> Makefile currently keys off the following for the different zImage
> 'types'
>
> image-$(CONFIG_PPC_PSERIES) += zImage.pseries
> image-$(CONFIG_PPC_MAPLE) += zImage.pseries
> image-$(CONFIG_PPC_IBM_CELL_BLADE) += zImage.pseries
> image-$(CONFIG_PPC_CHRP) += zImage.chrp
> image-$(CONFIG_PPC_PMAC) += zImage.pmac
> image-$(CONFIG_DEFAULT_UIMAGE) += uImage
>
> My original point really was that if I have a ppc 'embedded' board
> which I don't want to classify/define as
> PSERIES/MAPLE/CELL_BLADE/CHRP/PMAC, and I don't want to generate a
> uImage, I think there needs to be another definition, something like
> CONFIG_DEFAULT_ZIMAGE (similar to how CONFIG_DEFAULT_UIMAGE is used in
> some of the existing /power platform defs to create a uImage) which
> would be used to produce a 'normal' zImage type (zImage.pseries?).
Yeah, that's what the zImage.pseries is :) Bad name I agree.
> Basically - a definition analogous to the exisiting
> CONFIG_DEFAULT_UIMAGE, but for zImage. It would be used in a similar
> way - where any platform could select in its configuration to result
> in a 'normal' zImage being created (indeed, could
> PPC_PSERIES/MAPLE/BLADE just select this more generic definition and
> the Makefile use it instead?)
Ben.
^ permalink raw reply
* Re: [patch 08/16] powerpc: remove EMBEDDED6xx Kconfig entry
From: Olof Johansson @ 2006-11-03 20:53 UTC (permalink / raw)
To: Benjamin Herrenschmidt; +Cc: linuxppc-dev, paulus
In-Reply-To: <1162586775.10630.92.camel@localhost.localdomain>
On Sat, 04 Nov 2006 07:46:15 +1100 Benjamin Herrenschmidt <benh@kernel.crashing.org> wrote:
> Yes. Though I hope we'll see some alternatives to uboot soon
>
> /me looks towards ojn and segher....
There's already PIBS, isn't there?
-Olof
^ permalink raw reply
* [PATCH/RFC] Hookable IO operations
From: Benjamin Herrenschmidt @ 2006-11-03 21:12 UTC (permalink / raw)
To: linuxppc-dev list
This patch reworks the way iSeries hooks on PCI IO operations (both MMIO
and PIO) and provides a generic way for other platforms to do so (we
have need to do that for various other platforms).
While reworking the IO ops, I ended up doing some spring cleaning in
io.h and eeh.h which I might want to split into 2 or 3 patches (among
others, eeh.h had a lot of useless stuff in it) and I sitll need to do
hooks for the insw/insl/... versions of the ops, along with handling the
iomap case (probably by falling back to lib/iomap.c when INDIRECT_PCI_IO
is set).
A side effect is that EEH for PIO should work now (it used to pass IO
ports down to the eeh address check functions which is bogus).
Since I need that to fix some issues with Cell fairly urgently, I plan
to push that to 2.6.20 when the merge window opens, so please comment
asap :)
Oh, also, in the long run, I might also make EEH use the hooks instead
of wrapping at the toplevel, which would make things even cleaner and
relegate EEH completely in platforms/iseries, but we have to measure the
performance impact there (though it's really only on MMIO reads)
iSeries boots with that patch.
Not for merge yet, so no signed-off-yet... Diffstat is pretty nice
overall:
arch/powerpc/Kconfig | 5
arch/powerpc/kernel/setup_64.c | 45 +++
arch/powerpc/platforms/iseries/pci.c | 356 ++++++------------------
include/asm-powerpc/eeh.h | 91 ------
include/asm-powerpc/io.h | 506 ++++++++++++++++++-----------------
5 files changed, 403 insertions(+), 600 deletions(-)
Index: linux-cell/include/asm-powerpc/io.h
===================================================================
--- linux-cell.orig/include/asm-powerpc/io.h 2006-11-03 15:33:33.000000000 +1100
+++ linux-cell/include/asm-powerpc/io.h 2006-11-03 18:57:46.000000000 +1100
@@ -31,57 +31,111 @@ extern int check_legacy_ioport(unsigned
#define SLOW_DOWN_IO
+/*
+ *
+ * Low level MMIO accessors
+ *
+ * This provides the non-bus specific accessors to MMIO. Those are PowerPC
+ * specific and thus shouldn't be used in generic code. The accessors
+ * provided here are:
+ *
+ * in_8, in_le16, in_be16, in_le32, in_be32, in_le64, in_be64
+ * out_8, out_le16, out_be16, out_le32, out_be32, out_le64, out_be64
+ * _insb, _insw_ns, _insl_ns, _outsb, _outsw_ns, _outsl_ns
+ *
+ * Those operate direction on a kernel virtual address. Note that the prototype
+ * for the out_* accessors has the arguments in opposite order from the usual
+ * linux PCI accessors. Unlike those, they take the address first and the value
+ * next.
+ *
+ * Note: I might drop the _ns suffix on the stream operations soon as it is
+ * simply normal for stream operations to not swap in the first place.
+ *
+ */
+
+#define DEF_MMIO_IN(name, type, insn) \
+static inline type in_##name(const volatile type __iomem *addr) \
+{ \
+ type ret; \
+ __asm__ __volatile__("sync;" insn ";twi 0,%0,0;isync" \
+ : "=r" (ret) : "r" (addr), "m" (*addr)); \
+ return ret; \
+}
+
+#define DEF_MMIO_OUT(name, type, insn) \
+static inline void out_##name(volatile type __iomem *addr, type val) \
+{ \
+ __asm__ __volatile__("sync;" insn \
+ : "=m" (*addr) : "r" (val), "r" (addr)); \
+ get_paca()->io_sync = 1; \
+}
+
+
+#define DEF_MMIO_IN_BE(pfx, size, insn) \
+ DEF_MMIO_IN(pfx##size, u##size, __stringify(insn)"%U2%X2 %0,%2")
+#define DEF_MMIO_IN_LE(pfx, size, insn) \
+ DEF_MMIO_IN(pfx##size, u##size, __stringify(insn)" %0,0,%1")
+
+#define DEF_MMIO_OUT_BE(pfx, size, insn) \
+ DEF_MMIO_OUT(pfx##size, u##size, __stringify(insn)"%U0%X0 %1,%0")
+#define DEF_MMIO_OUT_LE(pfx, size, insn) \
+ DEF_MMIO_OUT(pfx##size, u##size, __stringify(insn)" %1,0,%2")
+
+DEF_MMIO_IN_BE( , 8, lbz);
+DEF_MMIO_IN_BE(be, 16, lhz);
+DEF_MMIO_IN_BE(be, 32, lwz);
+DEF_MMIO_IN_BE(be, 64, ld);
+DEF_MMIO_IN_LE(le, 16, lhbrx);
+DEF_MMIO_IN_LE(le, 32, lwbrx);
+
+DEF_MMIO_OUT_BE( , 8, stb);
+DEF_MMIO_OUT_BE(be, 16, sth);
+DEF_MMIO_OUT_BE(be, 32, stw);
+DEF_MMIO_OUT_BE(be, 64, std);
+DEF_MMIO_OUT_LE(le, 16, sthbrx);
+DEF_MMIO_OUT_LE(le, 32, stwbrx);
+
+/* There is no asm instructions for 64 bits reverse loads and stores */
+static inline u64 in_le64(const volatile u64 __iomem *addr)
+{
+ return le64_to_cpu(in_le64(addr));
+}
+
+static inline void out_le64(volatile u64 __iomem *addr, u64 val)
+{
+ out_le64(addr, cpu_to_le64(val));
+}
+
+/*
+ * IO stream instructions are defined out of line
+ */
+extern void _insb(volatile u8 __iomem *port, void *buf, long count);
+extern void _outsb(volatile u8 __iomem *port, const void *buf, long count);
+extern void _insw_ns(volatile u16 __iomem *port, void *buf, long count);
+extern void _outsw_ns(volatile u16 __iomem *port, const void *buf, long count);
+extern void _insl_ns(volatile u32 __iomem *port, void *buf, long count);
+extern void _outsl_ns(volatile u32 __iomem *port, const void *buf, long count);
+
+
+
+/*
+ *
+ * PCI and standard ISA accessors
+ *
+ * Those are globally defined linux accessors for devices on PCI or ISA
+ * busses. They follow the Linux defined semantics. The current implementation
+ * for PowerPC is as close as possible to the x86 version of these, and thus
+ * provides fairly heavy weight barriers for the non-raw versions
+ *
+ */
+
extern unsigned long isa_io_base;
extern unsigned long pci_io_base;
-#ifdef CONFIG_PPC_ISERIES
-extern int in_8(const volatile unsigned char __iomem *addr);
-extern void out_8(volatile unsigned char __iomem *addr, int val);
-extern int in_le16(const volatile unsigned short __iomem *addr);
-extern int in_be16(const volatile unsigned short __iomem *addr);
-extern void out_le16(volatile unsigned short __iomem *addr, int val);
-extern void out_be16(volatile unsigned short __iomem *addr, int val);
-extern unsigned in_le32(const volatile unsigned __iomem *addr);
-extern unsigned in_be32(const volatile unsigned __iomem *addr);
-extern void out_le32(volatile unsigned __iomem *addr, int val);
-extern void out_be32(volatile unsigned __iomem *addr, int val);
-extern unsigned long in_le64(const volatile unsigned long __iomem *addr);
-extern unsigned long in_be64(const volatile unsigned long __iomem *addr);
-extern void out_le64(volatile unsigned long __iomem *addr, unsigned long val);
-extern void out_be64(volatile unsigned long __iomem *addr, unsigned long val);
-
-extern unsigned char __raw_readb(const volatile void __iomem *addr);
-extern unsigned short __raw_readw(const volatile void __iomem *addr);
-extern unsigned int __raw_readl(const volatile void __iomem *addr);
-extern unsigned long __raw_readq(const volatile void __iomem *addr);
-extern void __raw_writeb(unsigned char v, volatile void __iomem *addr);
-extern void __raw_writew(unsigned short v, volatile void __iomem *addr);
-extern void __raw_writel(unsigned int v, volatile void __iomem *addr);
-extern void __raw_writeq(unsigned long v, volatile void __iomem *addr);
-
-extern void memset_io(volatile void __iomem *addr, int c, unsigned long n);
-extern void memcpy_fromio(void *dest, const volatile void __iomem *src,
- unsigned long n);
-extern void memcpy_toio(volatile void __iomem *dest, const void *src,
- unsigned long n);
-
-#else /* CONFIG_PPC_ISERIES */
-
-#define in_8(addr) __in_8((addr))
-#define out_8(addr, val) __out_8((addr), (val))
-#define in_le16(addr) __in_le16((addr))
-#define in_be16(addr) __in_be16((addr))
-#define out_le16(addr, val) __out_le16((addr), (val))
-#define out_be16(addr, val) __out_be16((addr), (val))
-#define in_le32(addr) __in_le32((addr))
-#define in_be32(addr) __in_be32((addr))
-#define out_le32(addr, val) __out_le32((addr), (val))
-#define out_be32(addr, val) __out_be32((addr), (val))
-#define in_le64(addr) __in_le64((addr))
-#define in_be64(addr) __in_be64((addr))
-#define out_le64(addr, val) __out_le64((addr), (val))
-#define out_be64(addr, val) __out_be64((addr), (val))
+/*
+ * Non ordered and non-swapping "raw" accessors
+ */
static inline unsigned char __raw_readb(const volatile void __iomem *addr)
{
@@ -115,17 +169,133 @@ static inline void __raw_writeq(unsigned
{
*(volatile unsigned long __force *)addr = v;
}
-#define memset_io(a,b,c) eeh_memset_io((a),(b),(c))
-#define memcpy_fromio(a,b,c) eeh_memcpy_fromio((a),(b),(c))
-#define memcpy_toio(a,b,c) eeh_memcpy_toio((a),(b),(c))
-#endif /* CONFIG_PPC_ISERIES */
+
+/*
+ * PCI IO accessors.
+ *
+ * Right now, we still use the eeh versions inline but that might change
+ * as EEH can use the new hook mecanism, provided it doesn't impact
+ * performances too much
+ */
+
+#include <asm/eeh.h>
+
+#define DEF_PCI_DT_b u8
+#define DEF_PCI_DT_w u16
+#define DEF_PCI_DT_l u32
+#define DEF_PCI_DT_q u64
+
+#define __do_writeb(val, addr) out_8(addr, val)
+#define __do_writew(val, addr) out_le16(addr, val)
+#define __do_writel(val, addr) out_le32(addr, val)
+#define __do_writeq(val, addr) out_le64(addr, val)
+
+#ifdef CONFIG_PPC_INDIRECT_IO
+#define DEF_PCI_HOOK(x) x
+#else
+#define DEF_PCI_HOOK(x) NULL
+#endif
+
+#define DEF_PCI_AC_IN_MMIO(ts) \
+extern DEF_PCI_DT_##ts (*__ind_read##ts)(const volatile void __iomem * addr); \
+static inline DEF_PCI_DT_##ts read##ts(const volatile void __iomem * addr) \
+{ \
+ if (DEF_PCI_HOOK(__ind_read##ts) != NULL) \
+ return __ind_read##ts(addr); \
+ return eeh_read##ts(addr); \
+}
+
+#define DEF_PCI_AC_IN_PIO(ts) \
+extern DEF_PCI_DT_##ts (*__ind_in##ts)(unsigned long port); \
+static inline DEF_PCI_DT_##ts in##ts(unsigned long port) \
+{ \
+ if (DEF_PCI_HOOK(__ind_in##ts) != NULL) \
+ return __ind_in##ts(port); \
+ return read##ts((void __iomem *)pci_io_base + port); \
+}
+
+#define DEF_PCI_AC_OUT_MMIO(ts) \
+extern void (*__ind_write##ts)(DEF_PCI_DT_##ts val, \
+ volatile void __iomem *addr); \
+static inline void write##ts(DEF_PCI_DT_##ts val, volatile void __iomem *addr) \
+{ \
+ if (DEF_PCI_HOOK(__ind_write##ts) != NULL) \
+ __ind_write##ts(val, addr); \
+ else \
+ __do_write##ts(val, addr); \
+}
+
+#define DEF_PCI_AC_OUT_PIO(ts) \
+extern void (*__ind_out##ts)(DEF_PCI_DT_##ts val, unsigned long port); \
+static inline void out##ts(DEF_PCI_DT_##ts val, unsigned long port) \
+{ \
+ if (DEF_PCI_HOOK(__ind_out##ts) != NULL) \
+ __ind_out##ts(val, port); \
+ else \
+ write##ts(val, (void __iomem *)pci_io_base + port); \
+}
+
+#define DEF_PCI_AC_MMIO(ts, dir) DEF_PCI_AC_##dir##_MMIO(ts)
+#define DEF_PCI_AC_PIO(ts, dir) DEF_PCI_AC_##dir##_PIO(ts)
+
+#define DEF_PCI_AC(ts, dir) DEF_PCI_AC_MMIO(ts, dir) \
+ DEF_PCI_AC_PIO(ts, dir)
+DEF_PCI_AC(b, IN)
+DEF_PCI_AC(w, IN)
+DEF_PCI_AC(l, IN)
+DEF_PCI_AC_MMIO(q, IN)
+DEF_PCI_AC(b, OUT)
+DEF_PCI_AC(w, OUT)
+DEF_PCI_AC(l, OUT)
+DEF_PCI_AC_MMIO(q, OUT)
+
+/* We still use EEH versions for now. Ultimately, we might just get rid of
+ * EEH in here and use it as a set of __memset_io etc... hooks
+ */
+
+extern void (*__memset_io)(volatile void __iomem *addr, int c,
+ unsigned long n);
+extern void (*__memcpy_fromio)(void *dest, const volatile void __iomem *src,
+ unsigned long n);
+extern void (*__memcpy_toio)(volatile void __iomem *dest, const void *src,
+ unsigned long n);
+
+static inline void memset_io(volatile void __iomem *addr, int c,
+ unsigned long n)
+{
+ if (DEF_PCI_HOOK(__memset_io))
+ __memset_io(addr, c, n);
+ else
+ eeh_memset_io(addr, c, n);
+}
+
+static inline void memcpy_fromio(void *dest, const volatile void __iomem *src,
+ unsigned long n)
+{
+ if (DEF_PCI_HOOK(__memcpy_fromio))
+ __memcpy_fromio(dest, src, n);
+ else
+ eeh_memcpy_fromio(dest, src, n);
+}
+
+static inline void memcpy_toio(volatile void __iomem *dest, const void *src,
+ unsigned long n)
+{
+ if (DEF_PCI_HOOK(__memcpy_toio))
+ __memcpy_toio(dest, src, n);
+ else
+ eeh_memcpy_toio(dest, src, n);
+}
/*
* The insw/outsw/insl/outsl macros don't do byte-swapping.
* They are only used in practice for transferring buffers which
* are arrays of bytes, and byte-swapping is not appropriate in
- * that case. - paulus */
+ * that case. - paulus
+ *
+ * We need to add hooking mecanisms to these
+ */
#define insb(port, buf, ns) eeh_insb((port), (buf), (ns))
#define insw(port, buf, ns) eeh_insw_ns((port), (buf), (ns))
#define insl(port, buf, nl) eeh_insl_ns((port), (buf), (nl))
@@ -134,33 +304,39 @@ static inline void __raw_writeq(unsigned
#define outsw(port, buf, ns) _outsw_ns((u16 __iomem *)((port)+pci_io_base), (buf), (ns))
#define outsl(port, buf, nl) _outsl_ns((u32 __iomem *)((port)+pci_io_base), (buf), (nl))
-#define readb(addr) eeh_readb(addr)
-#define readw(addr) eeh_readw(addr)
-#define readl(addr) eeh_readl(addr)
-#define readq(addr) eeh_readq(addr)
-#define writeb(data, addr) eeh_writeb((data), (addr))
-#define writew(data, addr) eeh_writew((data), (addr))
-#define writel(data, addr) eeh_writel((data), (addr))
-#define writeq(data, addr) eeh_writeq((data), (addr))
-#define inb(port) eeh_inb((unsigned long)port)
-#define outb(val, port) eeh_outb(val, (unsigned long)port)
-#define inw(port) eeh_inw((unsigned long)port)
-#define outw(val, port) eeh_outw(val, (unsigned long)port)
-#define inl(port) eeh_inl((unsigned long)port)
-#define outl(val, port) eeh_outl(val, (unsigned long)port)
+
+/* Nothing to do */
+
+#define dma_cache_inv(_start,_size) do { } while (0)
+#define dma_cache_wback(_start,_size) do { } while (0)
+#define dma_cache_wback_inv(_start,_size) do { } while (0)
+
+
+/*
+ * Convert a physical pointer to a virtual kernel pointer for /dev/mem
+ * access
+ */
+#define xlate_dev_mem_ptr(p) __va(p)
+
+/*
+ * Convert a virtual cached pointer to an uncached pointer
+ */
+#define xlate_dev_kmem_ptr(p) p
+
+/*
+ * We don't do relaxed operations yet, at least not with this semantic
+ */
#define readb_relaxed(addr) readb(addr)
#define readw_relaxed(addr) readw(addr)
#define readl_relaxed(addr) readl(addr)
#define readq_relaxed(addr) readq(addr)
-extern void _insb(volatile u8 __iomem *port, void *buf, long count);
-extern void _outsb(volatile u8 __iomem *port, const void *buf, long count);
-extern void _insw_ns(volatile u16 __iomem *port, void *buf, long count);
-extern void _outsw_ns(volatile u16 __iomem *port, const void *buf, long count);
-extern void _insl_ns(volatile u32 __iomem *port, void *buf, long count);
-extern void _outsl_ns(volatile u32 __iomem *port, const void *buf, long count);
-
+/*
+ * Enforce synchronisation of stores vs. spin_unlock
+ * (this does it explicitely, though our implementation of spin_unlock
+ * does it implicitely too)
+ */
static inline void mmiowb(void)
{
unsigned long tmp;
@@ -170,6 +346,19 @@ static inline void mmiowb(void)
: "memory");
}
+static inline void iosync(void)
+{
+ __asm__ __volatile__ ("sync" : : : "memory");
+}
+
+/* Enforce in-order execution of data I/O.
+ * No distinction between read/write on PPC; use eieio for all three.
+ */
+#define iobarrier_rw() eieio()
+#define iobarrier_r() eieio()
+#define iobarrier_w() eieio()
+
+
/*
* output pause versions need a delay at least for the
* w83c105 ide controller in a p610.
@@ -254,177 +443,6 @@ static inline void * phys_to_virt(unsign
*/
#define BIO_VMERGE_BOUNDARY 0
-static inline void iosync(void)
-{
- __asm__ __volatile__ ("sync" : : : "memory");
-}
-
-/* Enforce in-order execution of data I/O.
- * No distinction between read/write on PPC; use eieio for all three.
- */
-#define iobarrier_rw() eieio()
-#define iobarrier_r() eieio()
-#define iobarrier_w() eieio()
-
-/*
- * 8, 16 and 32 bit, big and little endian I/O operations, with barrier.
- * These routines do not perform EEH-related I/O address translation,
- * and should not be used directly by device drivers. Use inb/readb
- * instead.
- */
-static inline int __in_8(const volatile unsigned char __iomem *addr)
-{
- int ret;
-
- __asm__ __volatile__("sync; lbz%U1%X1 %0,%1; twi 0,%0,0; isync"
- : "=r" (ret) : "m" (*addr));
- return ret;
-}
-
-static inline void __out_8(volatile unsigned char __iomem *addr, int val)
-{
- __asm__ __volatile__("sync; stb%U0%X0 %1,%0"
- : "=m" (*addr) : "r" (val));
- get_paca()->io_sync = 1;
-}
-
-static inline int __in_le16(const volatile unsigned short __iomem *addr)
-{
- int ret;
-
- __asm__ __volatile__("sync; lhbrx %0,0,%1; twi 0,%0,0; isync"
- : "=r" (ret) : "r" (addr), "m" (*addr));
- return ret;
-}
-
-static inline int __in_be16(const volatile unsigned short __iomem *addr)
-{
- int ret;
-
- __asm__ __volatile__("sync; lhz%U1%X1 %0,%1; twi 0,%0,0; isync"
- : "=r" (ret) : "m" (*addr));
- return ret;
-}
-
-static inline void __out_le16(volatile unsigned short __iomem *addr, int val)
-{
- __asm__ __volatile__("sync; sthbrx %1,0,%2"
- : "=m" (*addr) : "r" (val), "r" (addr));
- get_paca()->io_sync = 1;
-}
-
-static inline void __out_be16(volatile unsigned short __iomem *addr, int val)
-{
- __asm__ __volatile__("sync; sth%U0%X0 %1,%0"
- : "=m" (*addr) : "r" (val));
- get_paca()->io_sync = 1;
-}
-
-static inline unsigned __in_le32(const volatile unsigned __iomem *addr)
-{
- unsigned ret;
-
- __asm__ __volatile__("sync; lwbrx %0,0,%1; twi 0,%0,0; isync"
- : "=r" (ret) : "r" (addr), "m" (*addr));
- return ret;
-}
-
-static inline unsigned __in_be32(const volatile unsigned __iomem *addr)
-{
- unsigned ret;
-
- __asm__ __volatile__("sync; lwz%U1%X1 %0,%1; twi 0,%0,0; isync"
- : "=r" (ret) : "m" (*addr));
- return ret;
-}
-
-static inline void __out_le32(volatile unsigned __iomem *addr, int val)
-{
- __asm__ __volatile__("sync; stwbrx %1,0,%2" : "=m" (*addr)
- : "r" (val), "r" (addr));
- get_paca()->io_sync = 1;
-}
-
-static inline void __out_be32(volatile unsigned __iomem *addr, int val)
-{
- __asm__ __volatile__("sync; stw%U0%X0 %1,%0"
- : "=m" (*addr) : "r" (val));
- get_paca()->io_sync = 1;
-}
-
-static inline unsigned long __in_le64(const volatile unsigned long __iomem *addr)
-{
- unsigned long tmp, ret;
-
- __asm__ __volatile__(
- "sync\n"
- "ld %1,0(%2)\n"
- "twi 0,%1,0\n"
- "isync\n"
- "rldimi %0,%1,5*8,1*8\n"
- "rldimi %0,%1,3*8,2*8\n"
- "rldimi %0,%1,1*8,3*8\n"
- "rldimi %0,%1,7*8,4*8\n"
- "rldicl %1,%1,32,0\n"
- "rlwimi %0,%1,8,8,31\n"
- "rlwimi %0,%1,24,16,23\n"
- : "=r" (ret) , "=r" (tmp) : "b" (addr) , "m" (*addr));
- return ret;
-}
-
-static inline unsigned long __in_be64(const volatile unsigned long __iomem *addr)
-{
- unsigned long ret;
-
- __asm__ __volatile__("sync; ld%U1%X1 %0,%1; twi 0,%0,0; isync"
- : "=r" (ret) : "m" (*addr));
- return ret;
-}
-
-static inline void __out_le64(volatile unsigned long __iomem *addr, unsigned long val)
-{
- unsigned long tmp;
-
- __asm__ __volatile__(
- "rldimi %0,%1,5*8,1*8\n"
- "rldimi %0,%1,3*8,2*8\n"
- "rldimi %0,%1,1*8,3*8\n"
- "rldimi %0,%1,7*8,4*8\n"
- "rldicl %1,%1,32,0\n"
- "rlwimi %0,%1,8,8,31\n"
- "rlwimi %0,%1,24,16,23\n"
- "sync\n"
- "std %0,0(%3)"
- : "=&r" (tmp) , "=&r" (val) : "1" (val) , "b" (addr) , "m" (*addr));
- get_paca()->io_sync = 1;
-}
-
-static inline void __out_be64(volatile unsigned long __iomem *addr, unsigned long val)
-{
- __asm__ __volatile__("sync; std%U0%X0 %1,%0" : "=m" (*addr) : "r" (val));
- get_paca()->io_sync = 1;
-}
-
-#include <asm/eeh.h>
-
-/* Nothing to do */
-
-#define dma_cache_inv(_start,_size) do { } while (0)
-#define dma_cache_wback(_start,_size) do { } while (0)
-#define dma_cache_wback_inv(_start,_size) do { } while (0)
-
-
-/*
- * Convert a physical pointer to a virtual kernel pointer for /dev/mem
- * access
- */
-#define xlate_dev_mem_ptr(p) __va(p)
-
-/*
- * Convert a virtual cached pointer to an uncached pointer
- */
-#define xlate_dev_kmem_ptr(p) p
-
#endif /* __KERNEL__ */
#endif /* CONFIG_PPC64 */
Index: linux-cell/arch/powerpc/Kconfig
===================================================================
--- linux-cell.orig/arch/powerpc/Kconfig 2006-11-03 15:33:33.000000000 +1100
+++ linux-cell/arch/powerpc/Kconfig 2006-11-03 15:52:58.000000000 +1100
@@ -389,6 +389,7 @@ config PPC_PSERIES
config PPC_ISERIES
bool "IBM Legacy iSeries"
depends on PPC_MULTIPLATFORM && PPC64
+ select PPC_INDIRECT_IO
config PPC_CHRP
bool "Common Hardware Reference Platform (CHRP) based machines"
@@ -534,6 +535,10 @@ config PPC_970_NAP
bool
default n
+config PPC_INDIRECT_IO
+ bool
+ default n
+
source "drivers/cpufreq/Kconfig"
config CPU_FREQ_PMAC
Index: linux-cell/arch/powerpc/kernel/setup_64.c
===================================================================
--- linux-cell.orig/arch/powerpc/kernel/setup_64.c 2006-11-03 15:52:54.000000000 +1100
+++ linux-cell/arch/powerpc/kernel/setup_64.c 2006-11-03 18:51:14.000000000 +1100
@@ -599,3 +599,48 @@ void __init setup_per_cpu_areas(void)
}
}
#endif
+
+
+#ifdef CONFIG_PPC_INDIRECT_IO
+
+#define EXP_PCI_AC_IN_MMIO(ts) \
+DEF_PCI_DT_##ts (*__ind_read##ts)(const volatile void __iomem * addr); \
+EXPORT_SYMBOL(__ind_read##ts);
+
+#define EXP_PCI_AC_IN_PIO(ts) \
+DEF_PCI_DT_##ts (*__ind_in##ts)(unsigned long port); \
+EXPORT_SYMBOL(__ind_in##ts);
+
+#define EXP_PCI_AC_OUT_MMIO(ts) \
+void (*__ind_write##ts)(DEF_PCI_DT_##ts val, \
+ volatile void __iomem *addr); \
+EXPORT_SYMBOL(__ind_write##ts);
+
+#define EXP_PCI_AC_OUT_PIO(ts) \
+void (*__ind_out##ts)(DEF_PCI_DT_##ts val, unsigned long port); \
+EXPORT_SYMBOL(__ind_out##ts);
+
+#define EXP_PCI_AC_MMIO(ts, dir) EXP_PCI_AC_##dir##_MMIO(ts)
+#define EXP_PCI_AC_PIO(ts, dir) EXP_PCI_AC_##dir##_PIO(ts)
+
+#define EXP_PCI_AC(ts, dir) EXP_PCI_AC_MMIO(ts, dir) \
+ EXP_PCI_AC_PIO(ts, dir)
+EXP_PCI_AC(b, IN)
+EXP_PCI_AC(w, IN)
+EXP_PCI_AC(l, IN)
+EXP_PCI_AC_MMIO(q, IN)
+EXP_PCI_AC(b, OUT)
+EXP_PCI_AC(w, OUT)
+EXP_PCI_AC(l, OUT)
+EXP_PCI_AC_MMIO(q, OUT)
+
+void (*__memset_io)(volatile void __iomem *addr, int c, unsigned long n);
+void (*__memcpy_fromio)(void *dest, const volatile void __iomem *src,
+ unsigned long n);
+void (*__memcpy_toio)(volatile void __iomem *dest, const void *src,
+ unsigned long n);
+EXPORT_SYMBOL(__memset_io);
+EXPORT_SYMBOL(__memcpy_fromio);
+EXPORT_SYMBOL(__memcpy_toio);
+#endif /* CONFIG_PPC_INDIRECT_IO */
+
Index: linux-cell/arch/powerpc/platforms/iseries/pci.c
===================================================================
--- linux-cell.orig/arch/powerpc/platforms/iseries/pci.c 2006-11-03 15:37:23.000000000 +1100
+++ linux-cell/arch/powerpc/platforms/iseries/pci.c 2006-11-03 18:54:13.000000000 +1100
@@ -156,53 +156,6 @@ static void pci_Log_Error(char *Error_Te
}
/*
- * iSeries_pcibios_init
- *
- * Description:
- * This function checks for all possible system PCI host bridges that connect
- * PCI buses. The system hypervisor is queried as to the guest partition
- * ownership status. A pci_controller is built for any bus which is partially
- * owned or fully owned by this guest partition.
- */
-void iSeries_pcibios_init(void)
-{
- struct pci_controller *phb;
- struct device_node *root = of_find_node_by_path("/");
- struct device_node *node = NULL;
-
- if (root == NULL) {
- printk(KERN_CRIT "iSeries_pcibios_init: can't find root "
- "of device tree\n");
- return;
- }
- while ((node = of_get_next_child(root, node)) != NULL) {
- HvBusNumber bus;
- const u32 *busp;
-
- if ((node->type == NULL) || (strcmp(node->type, "pci") != 0))
- continue;
-
- busp = get_property(node, "bus-range", NULL);
- if (busp == NULL)
- continue;
- bus = *busp;
- printk("bus %d appears to exist\n", bus);
- phb = pcibios_alloc_controller(node);
- if (phb == NULL)
- continue;
-
- phb->pci_mem_offset = phb->local_number = bus;
- phb->first_busno = bus;
- phb->last_busno = bus;
- phb->ops = &iSeries_pci_ops;
- }
-
- of_node_put(root);
-
- pci_devs_phb_init();
-}
-
-/*
* iSeries_pci_final_fixup(void)
*/
void __init iSeries_pci_final_fixup(void)
@@ -438,13 +391,9 @@ static inline struct device_node *xlate_
/*
* Read MM I/O Instructions for the iSeries
* On MM I/O error, all ones are returned and iSeries_pci_IoError is cal
- * else, data is returned in big Endian format.
- *
- * iSeries_Read_Byte = Read Byte ( 8 bit)
- * iSeries_Read_Word = Read Word (16 bit)
- * iSeries_Read_Long = Read Long (32 bit)
+ * else, data is returned in little Endian format.
*/
-static u8 iSeries_Read_Byte(const volatile void __iomem *IoAddress)
+static u8 iseries_readb(const volatile void __iomem *IoAddress)
{
u64 BarOffset;
u64 dsa;
@@ -462,7 +411,8 @@ static u8 iSeries_Read_Byte(const volati
num_printed = 0;
}
if (num_printed++ < 10)
- printk(KERN_ERR "iSeries_Read_Byte: invalid access at IO address %p\n", IoAddress);
+ printk(KERN_ERR "iSeries_Read_Byte: invalid access at IO address %p\n",
+ IoAddress);
return 0xff;
}
do {
@@ -472,7 +422,7 @@ static u8 iSeries_Read_Byte(const volati
return (u8)ret.value;
}
-static u16 iSeries_Read_Word(const volatile void __iomem *IoAddress)
+static u16 iseries_readw(const volatile void __iomem *IoAddress)
{
u64 BarOffset;
u64 dsa;
@@ -490,7 +440,8 @@ static u16 iSeries_Read_Word(const volat
num_printed = 0;
}
if (num_printed++ < 10)
- printk(KERN_ERR "iSeries_Read_Word: invalid access at IO address %p\n", IoAddress);
+ printk(KERN_ERR "iSeries_Read_Word: invalid access at IO address %p\n",
+ IoAddress);
return 0xffff;
}
do {
@@ -498,10 +449,10 @@ static u16 iSeries_Read_Word(const volat
BarOffset, 0);
} while (CheckReturnCode("RDW", DevNode, &retry, ret.rc) != 0);
- return swab16((u16)ret.value);
+ return cpu_to_le16((u16)ret.value);
}
-static u32 iSeries_Read_Long(const volatile void __iomem *IoAddress)
+static u32 iseries_readl(const volatile void __iomem *IoAddress)
{
u64 BarOffset;
u64 dsa;
@@ -519,7 +470,8 @@ static u32 iSeries_Read_Long(const volat
num_printed = 0;
}
if (num_printed++ < 10)
- printk(KERN_ERR "iSeries_Read_Long: invalid access at IO address %p\n", IoAddress);
+ printk(KERN_ERR "iSeries_Read_Long: invalid access at IO address %p\n",
+ IoAddress);
return 0xffffffff;
}
do {
@@ -527,17 +479,14 @@ static u32 iSeries_Read_Long(const volat
BarOffset, 0);
} while (CheckReturnCode("RDL", DevNode, &retry, ret.rc) != 0);
- return swab32((u32)ret.value);
+ return cpu_to_le32((u32)ret.value);
}
/*
* Write MM I/O Instructions for the iSeries
*
- * iSeries_Write_Byte = Write Byte (8 bit)
- * iSeries_Write_Word = Write Word(16 bit)
- * iSeries_Write_Long = Write Long(32 bit)
*/
-static void iSeries_Write_Byte(u8 data, volatile void __iomem *IoAddress)
+static void iseries_writeb(u8 data, volatile void __iomem *IoAddress)
{
u64 BarOffset;
u64 dsa;
@@ -563,7 +512,7 @@ static void iSeries_Write_Byte(u8 data,
} while (CheckReturnCode("WWB", DevNode, &retry, rc) != 0);
}
-static void iSeries_Write_Word(u16 data, volatile void __iomem *IoAddress)
+static void iseries_writew(u16 data, volatile void __iomem *IoAddress)
{
u64 BarOffset;
u64 dsa;
@@ -581,15 +530,16 @@ static void iSeries_Write_Word(u16 data,
num_printed = 0;
}
if (num_printed++ < 10)
- printk(KERN_ERR "iSeries_Write_Word: invalid access at IO address %p\n", IoAddress);
+ printk(KERN_ERR "iSeries_Write_Word: invalid access at IO address %p\n",
+ IoAddress);
return;
}
do {
- rc = HvCall4(HvCallPciBarStore16, dsa, BarOffset, swab16(data), 0);
+ rc = HvCall4(HvCallPciBarStore16, dsa, BarOffset, le16_to_cpu(data), 0);
} while (CheckReturnCode("WWW", DevNode, &retry, rc) != 0);
}
-static void iSeries_Write_Long(u32 data, volatile void __iomem *IoAddress)
+static void iseries_writel(u32 data, volatile void __iomem *IoAddress)
{
u64 BarOffset;
u64 dsa;
@@ -607,231 +557,107 @@ static void iSeries_Write_Long(u32 data,
num_printed = 0;
}
if (num_printed++ < 10)
- printk(KERN_ERR "iSeries_Write_Long: invalid access at IO address %p\n", IoAddress);
+ printk(KERN_ERR "iSeries_Write_Long: invalid access at IO address %p\n",
+ IoAddress);
return;
}
do {
- rc = HvCall4(HvCallPciBarStore32, dsa, BarOffset, swab32(data), 0);
+ rc = HvCall4(HvCallPciBarStore32, dsa, BarOffset, le32_to_cpu(data), 0);
} while (CheckReturnCode("WWL", DevNode, &retry, rc) != 0);
}
-extern unsigned char __raw_readb(const volatile void __iomem *addr)
-{
- BUG_ON(firmware_has_feature(FW_FEATURE_ISERIES));
-
- return *(volatile unsigned char __force *)addr;
-}
-EXPORT_SYMBOL(__raw_readb);
-
-extern unsigned short __raw_readw(const volatile void __iomem *addr)
-{
- BUG_ON(firmware_has_feature(FW_FEATURE_ISERIES));
-
- return *(volatile unsigned short __force *)addr;
-}
-EXPORT_SYMBOL(__raw_readw);
-
-extern unsigned int __raw_readl(const volatile void __iomem *addr)
-{
- BUG_ON(firmware_has_feature(FW_FEATURE_ISERIES));
-
- return *(volatile unsigned int __force *)addr;
-}
-EXPORT_SYMBOL(__raw_readl);
-
-extern unsigned long __raw_readq(const volatile void __iomem *addr)
-{
- BUG_ON(firmware_has_feature(FW_FEATURE_ISERIES));
-
- return *(volatile unsigned long __force *)addr;
-}
-EXPORT_SYMBOL(__raw_readq);
-
-extern void __raw_writeb(unsigned char v, volatile void __iomem *addr)
-{
- BUG_ON(firmware_has_feature(FW_FEATURE_ISERIES));
-
- *(volatile unsigned char __force *)addr = v;
-}
-EXPORT_SYMBOL(__raw_writeb);
-
-extern void __raw_writew(unsigned short v, volatile void __iomem *addr)
-{
- BUG_ON(firmware_has_feature(FW_FEATURE_ISERIES));
-
- *(volatile unsigned short __force *)addr = v;
-}
-EXPORT_SYMBOL(__raw_writew);
-
-extern void __raw_writel(unsigned int v, volatile void __iomem *addr)
-{
- BUG_ON(firmware_has_feature(FW_FEATURE_ISERIES));
-
- *(volatile unsigned int __force *)addr = v;
-}
-EXPORT_SYMBOL(__raw_writel);
-
-extern void __raw_writeq(unsigned long v, volatile void __iomem *addr)
-{
- BUG_ON(firmware_has_feature(FW_FEATURE_ISERIES));
-
- *(volatile unsigned long __force *)addr = v;
-}
-EXPORT_SYMBOL(__raw_writeq);
-
-int in_8(const volatile unsigned char __iomem *addr)
+static void iseries_memset_io(volatile void __iomem *addr, int c, unsigned long n)
{
- if (firmware_has_feature(FW_FEATURE_ISERIES))
- return iSeries_Read_Byte(addr);
- return __in_8(addr);
-}
-EXPORT_SYMBOL(in_8);
-
-void out_8(volatile unsigned char __iomem *addr, int val)
-{
- if (firmware_has_feature(FW_FEATURE_ISERIES))
- iSeries_Write_Byte(val, addr);
- else
- __out_8(addr, val);
-}
-EXPORT_SYMBOL(out_8);
-
-int in_le16(const volatile unsigned short __iomem *addr)
-{
- if (firmware_has_feature(FW_FEATURE_ISERIES))
- return iSeries_Read_Word(addr);
- return __in_le16(addr);
-}
-EXPORT_SYMBOL(in_le16);
-
-int in_be16(const volatile unsigned short __iomem *addr)
-{
- BUG_ON(firmware_has_feature(FW_FEATURE_ISERIES));
-
- return __in_be16(addr);
-}
-EXPORT_SYMBOL(in_be16);
-
-void out_le16(volatile unsigned short __iomem *addr, int val)
-{
- if (firmware_has_feature(FW_FEATURE_ISERIES))
- iSeries_Write_Word(val, addr);
- else
- __out_le16(addr, val);
-}
-EXPORT_SYMBOL(out_le16);
-
-void out_be16(volatile unsigned short __iomem *addr, int val)
-{
- BUG_ON(firmware_has_feature(FW_FEATURE_ISERIES));
-
- __out_be16(addr, val);
-}
-EXPORT_SYMBOL(out_be16);
-
-unsigned in_le32(const volatile unsigned __iomem *addr)
-{
- if (firmware_has_feature(FW_FEATURE_ISERIES))
- return iSeries_Read_Long(addr);
- return __in_le32(addr);
-}
-EXPORT_SYMBOL(in_le32);
-
-unsigned in_be32(const volatile unsigned __iomem *addr)
-{
- BUG_ON(firmware_has_feature(FW_FEATURE_ISERIES));
-
- return __in_be32(addr);
-}
-EXPORT_SYMBOL(in_be32);
+ volatile char __iomem *d = addr;
-void out_le32(volatile unsigned __iomem *addr, int val)
-{
- if (firmware_has_feature(FW_FEATURE_ISERIES))
- iSeries_Write_Long(val, addr);
- else
- __out_le32(addr, val);
+ while (n-- > 0)
+ iseries_writeb(c, d++);
}
-EXPORT_SYMBOL(out_le32);
-void out_be32(volatile unsigned __iomem *addr, int val)
+static void iseries_memcpy_fromio(void *dest, const volatile void __iomem *src,
+ unsigned long n)
{
- BUG_ON(firmware_has_feature(FW_FEATURE_ISERIES));
+ char *d = dest;
+ const volatile char __iomem *s = src;
- __out_be32(addr, val);
+ while (n-- > 0)
+ *d++ = iseries_readb(s++);
}
-EXPORT_SYMBOL(out_be32);
-unsigned long in_le64(const volatile unsigned long __iomem *addr)
+static void iseries_memcpy_toio(volatile void __iomem *dest, const void *src,
+ unsigned long n)
{
- BUG_ON(firmware_has_feature(FW_FEATURE_ISERIES));
+ const char *s = src;
+ volatile char __iomem *d = dest;
- return __in_le64(addr);
+ while (n-- > 0)
+ iseries_writeb(*s++, d++);
}
-EXPORT_SYMBOL(in_le64);
-unsigned long in_be64(const volatile unsigned long __iomem *addr)
+static void __init iseries_setup_io_access(void)
{
- BUG_ON(firmware_has_feature(FW_FEATURE_ISERIES));
-
- return __in_be64(addr);
+ /* Note that we only set the ones we support. The other ones
+ * are kept to their native implementation which will fault
+ * since we are giving them tokens that match non-mapped areas.
+ * This is as good behaviour as the BUG() we used to have
+ */
+ __ind_readb = iseries_readb;
+ __ind_readw = iseries_readw;
+ __ind_readl = iseries_readl;
+ __ind_writeb = iseries_writeb;
+ __ind_writew = iseries_writew;
+ __ind_writel = iseries_writel;
+ __memset_io = iseries_memset_io;
+ __memcpy_fromio = iseries_memcpy_fromio;
+ __memcpy_toio = iseries_memcpy_toio;
}
-EXPORT_SYMBOL(in_be64);
-void out_le64(volatile unsigned long __iomem *addr, unsigned long val)
+/*
+ * iSeries_pcibios_init
+ *
+ * Description:
+ * This function checks for all possible system PCI host bridges that connect
+ * PCI buses. The system hypervisor is queried as to the guest partition
+ * ownership status. A pci_controller is built for any bus which is partially
+ * owned or fully owned by this guest partition.
+ */
+void __init iSeries_pcibios_init(void)
{
- BUG_ON(firmware_has_feature(FW_FEATURE_ISERIES));
+ struct pci_controller *phb;
+ struct device_node *root = of_find_node_by_path("/");
+ struct device_node *node = NULL;
- __out_le64(addr, val);
-}
-EXPORT_SYMBOL(out_le64);
+ iseries_setup_io_access();
-void out_be64(volatile unsigned long __iomem *addr, unsigned long val)
-{
- BUG_ON(firmware_has_feature(FW_FEATURE_ISERIES));
+ if (root == NULL) {
+ printk(KERN_CRIT "iSeries_pcibios_init: can't find root "
+ "of device tree\n");
+ return;
+ }
+ while ((node = of_get_next_child(root, node)) != NULL) {
+ HvBusNumber bus;
+ const u32 *busp;
- __out_be64(addr, val);
-}
-EXPORT_SYMBOL(out_be64);
+ if ((node->type == NULL) || (strcmp(node->type, "pci") != 0))
+ continue;
-void memset_io(volatile void __iomem *addr, int c, unsigned long n)
-{
- if (firmware_has_feature(FW_FEATURE_ISERIES)) {
- volatile char __iomem *d = addr;
+ busp = get_property(node, "bus-range", NULL);
+ if (busp == NULL)
+ continue;
+ bus = *busp;
+ printk("bus %d appears to exist\n", bus);
+ phb = pcibios_alloc_controller(node);
+ if (phb == NULL)
+ continue;
- while (n-- > 0) {
- iSeries_Write_Byte(c, d++);
- }
- } else
- eeh_memset_io(addr, c, n);
-}
-EXPORT_SYMBOL(memset_io);
+ phb->pci_mem_offset = phb->local_number = bus;
+ phb->first_busno = bus;
+ phb->last_busno = bus;
+ phb->ops = &iSeries_pci_ops;
+ }
-void memcpy_fromio(void *dest, const volatile void __iomem *src,
- unsigned long n)
-{
- if (firmware_has_feature(FW_FEATURE_ISERIES)) {
- char *d = dest;
- const volatile char __iomem *s = src;
+ of_node_put(root);
- while (n-- > 0) {
- *d++ = iSeries_Read_Byte(s++);
- }
- } else
- eeh_memcpy_fromio(dest, src, n);
+ pci_devs_phb_init();
}
-EXPORT_SYMBOL(memcpy_fromio);
-void memcpy_toio(volatile void __iomem *dest, const void *src, unsigned long n)
-{
- if (firmware_has_feature(FW_FEATURE_ISERIES)) {
- const char *s = src;
- volatile char __iomem *d = dest;
-
- while (n-- > 0) {
- iSeries_Write_Byte(*s++, d++);
- }
- } else
- eeh_memcpy_toio(dest, src, n);
-}
-EXPORT_SYMBOL(memcpy_toio);
Index: linux-cell/include/asm-powerpc/eeh.h
===================================================================
--- linux-cell.orig/include/asm-powerpc/eeh.h 2006-10-06 13:48:23.000000000 +1000
+++ linux-cell/include/asm-powerpc/eeh.h 2006-11-03 18:25:21.000000000 +1100
@@ -120,10 +120,6 @@ static inline u8 eeh_readb(const volatil
return eeh_check_failure(addr, val);
return val;
}
-static inline void eeh_writeb(u8 val, volatile void __iomem *addr)
-{
- out_8(addr, val);
-}
static inline u16 eeh_readw(const volatile void __iomem *addr)
{
@@ -132,21 +128,6 @@ static inline u16 eeh_readw(const volati
return eeh_check_failure(addr, val);
return val;
}
-static inline void eeh_writew(u16 val, volatile void __iomem *addr)
-{
- out_le16(addr, val);
-}
-static inline u16 eeh_raw_readw(const volatile void __iomem *addr)
-{
- u16 val = in_be16(addr);
- if (EEH_POSSIBLE_ERROR(val, u16))
- return eeh_check_failure(addr, val);
- return val;
-}
-static inline void eeh_raw_writew(u16 val, volatile void __iomem *addr) {
- volatile u16 __iomem *vaddr = (volatile u16 __iomem *) addr;
- out_be16(vaddr, val);
-}
static inline u32 eeh_readl(const volatile void __iomem *addr)
{
@@ -155,21 +136,6 @@ static inline u32 eeh_readl(const volati
return eeh_check_failure(addr, val);
return val;
}
-static inline void eeh_writel(u32 val, volatile void __iomem *addr)
-{
- out_le32(addr, val);
-}
-static inline u32 eeh_raw_readl(const volatile void __iomem *addr)
-{
- u32 val = in_be32(addr);
- if (EEH_POSSIBLE_ERROR(val, u32))
- return eeh_check_failure(addr, val);
- return val;
-}
-static inline void eeh_raw_writel(u32 val, volatile void __iomem *addr)
-{
- out_be32(addr, val);
-}
static inline u64 eeh_readq(const volatile void __iomem *addr)
{
@@ -178,21 +144,6 @@ static inline u64 eeh_readq(const volati
return eeh_check_failure(addr, val);
return val;
}
-static inline void eeh_writeq(u64 val, volatile void __iomem *addr)
-{
- out_le64(addr, val);
-}
-static inline u64 eeh_raw_readq(const volatile void __iomem *addr)
-{
- u64 val = in_be64(addr);
- if (EEH_POSSIBLE_ERROR(val, u64))
- return eeh_check_failure(addr, val);
- return val;
-}
-static inline void eeh_raw_writeq(u64 val, volatile void __iomem *addr)
-{
- out_be64(addr, val);
-}
#define EEH_CHECK_ALIGN(v,a) \
((((unsigned long)(v)) & ((a) - 1)) == 0)
@@ -292,48 +243,6 @@ static inline void eeh_memcpy_toio(volat
#undef EEH_CHECK_ALIGN
-static inline u8 eeh_inb(unsigned long port)
-{
- u8 val;
- val = in_8((u8 __iomem *)(port+pci_io_base));
- if (EEH_POSSIBLE_ERROR(val, u8))
- return eeh_check_failure((void __iomem *)(port), val);
- return val;
-}
-
-static inline void eeh_outb(u8 val, unsigned long port)
-{
- out_8((u8 __iomem *)(port+pci_io_base), val);
-}
-
-static inline u16 eeh_inw(unsigned long port)
-{
- u16 val;
- val = in_le16((u16 __iomem *)(port+pci_io_base));
- if (EEH_POSSIBLE_ERROR(val, u16))
- return eeh_check_failure((void __iomem *)(port), val);
- return val;
-}
-
-static inline void eeh_outw(u16 val, unsigned long port)
-{
- out_le16((u16 __iomem *)(port+pci_io_base), val);
-}
-
-static inline u32 eeh_inl(unsigned long port)
-{
- u32 val;
- val = in_le32((u32 __iomem *)(port+pci_io_base));
- if (EEH_POSSIBLE_ERROR(val, u32))
- return eeh_check_failure((void __iomem *)(port), val);
- return val;
-}
-
-static inline void eeh_outl(u32 val, unsigned long port)
-{
- out_le32((u32 __iomem *)(port+pci_io_base), val);
-}
-
/* in-string eeh macros */
static inline void eeh_insb(unsigned long port, void * buf, int ns)
{
^ permalink raw reply
* [PATCH/RFC 1/3] powerpc: of_platform improvements
From: Benjamin Herrenschmidt @ 2006-11-03 21:18 UTC (permalink / raw)
To: linuxppc-dev list
This is also something that I'll need in 2.6.20, so please comment asap.
It's close to final (that is +- bugs, I don't have any other feature I
plan to add there in this cycle).
This patch splits of_platform.c from of_device.c and adds mecanisms
for creating of_platform devices in "bulk" by walking the device-tree
down and following known bus types.
For example, it could allow platforms using SoC devices to register the
whole set of nodes there in one call.
A subsequent patch will add an of_platform_driver for PCI host bridges
that can discover PCI busses from the OF tree.
For comments only at this point, so no signed-off.
Index: linux-cell/arch/powerpc/kernel/of_device.c
===================================================================
--- linux-cell.orig/arch/powerpc/kernel/of_device.c 2006-10-26 17:22:37.000000000 +1000
+++ linux-cell/arch/powerpc/kernel/of_device.c 2006-10-26 17:23:06.000000000 +1000
@@ -9,30 +9,26 @@
#include <asm/of_device.h>
/**
- * of_match_device - Tell if an of_device structure has a matching
- * of_match structure
+ * of_match_node - Tell if an device_node has a matching of_match structure
* @ids: array of of device match structures to search in
- * @dev: the of device structure to match against
+ * @node: the of device structure to match against
*
- * Used by a driver to check whether an of_device present in the
- * system is in its list of supported devices.
+ * Low level utility function used by device matching.
*/
-const struct of_device_id *of_match_device(const struct of_device_id *matches,
- const struct of_device *dev)
+const struct of_device_id *of_match_node(const struct of_device_id *matches,
+ const struct device_node *node)
{
- if (!dev->node)
- return NULL;
while (matches->name[0] || matches->type[0] || matches->compatible[0]) {
int match = 1;
if (matches->name[0])
- match &= dev->node->name
- && !strcmp(matches->name, dev->node->name);
+ match &= node->name
+ && !strcmp(matches->name, node->name);
if (matches->type[0])
- match &= dev->node->type
- && !strcmp(matches->type, dev->node->type);
+ match &= node->type
+ && !strcmp(matches->type, node->type);
if (matches->compatible[0])
- match &= device_is_compatible(dev->node,
- matches->compatible);
+ match &= device_is_compatible(node,
+ matches->compatible);
if (match)
return matches;
matches++;
@@ -40,16 +36,21 @@ const struct of_device_id *of_match_devi
return NULL;
}
-static int of_platform_bus_match(struct device *dev, struct device_driver *drv)
+/**
+ * of_match_device - Tell if an of_device structure has a matching
+ * of_match structure
+ * @ids: array of of device match structures to search in
+ * @dev: the of device structure to match against
+ *
+ * Used by a driver to check whether an of_device present in the
+ * system is in its list of supported devices.
+ */
+const struct of_device_id *of_match_device(const struct of_device_id *matches,
+ const struct of_device *dev)
{
- struct of_device * of_dev = to_of_device(dev);
- struct of_platform_driver * of_drv = to_of_platform_driver(drv);
- const struct of_device_id * matches = of_drv->match_table;
-
- if (!matches)
- return 0;
-
- return of_match_device(matches, of_dev) != NULL;
+ if (!dev->node)
+ return NULL;
+ return of_match_node(matches, dev->node);
}
struct of_device *of_dev_get(struct of_device *dev)
@@ -71,96 +72,8 @@ void of_dev_put(struct of_device *dev)
put_device(&dev->dev);
}
-
-static int of_device_probe(struct device *dev)
-{
- int error = -ENODEV;
- struct of_platform_driver *drv;
- struct of_device *of_dev;
- const struct of_device_id *match;
-
- drv = to_of_platform_driver(dev->driver);
- of_dev = to_of_device(dev);
-
- if (!drv->probe)
- return error;
-
- of_dev_get(of_dev);
-
- match = of_match_device(drv->match_table, of_dev);
- if (match)
- error = drv->probe(of_dev, match);
- if (error)
- of_dev_put(of_dev);
-
- return error;
-}
-
-static int of_device_remove(struct device *dev)
-{
- struct of_device * of_dev = to_of_device(dev);
- struct of_platform_driver * drv = to_of_platform_driver(dev->driver);
-
- if (dev->driver && drv->remove)
- drv->remove(of_dev);
- return 0;
-}
-
-static int of_device_suspend(struct device *dev, pm_message_t state)
-{
- struct of_device * of_dev = to_of_device(dev);
- struct of_platform_driver * drv = to_of_platform_driver(dev->driver);
- int error = 0;
-
- if (dev->driver && drv->suspend)
- error = drv->suspend(of_dev, state);
- return error;
-}
-
-static int of_device_resume(struct device * dev)
-{
- struct of_device * of_dev = to_of_device(dev);
- struct of_platform_driver * drv = to_of_platform_driver(dev->driver);
- int error = 0;
-
- if (dev->driver && drv->resume)
- error = drv->resume(of_dev);
- return error;
-}
-
-struct bus_type of_platform_bus_type = {
- .name = "of_platform",
- .match = of_platform_bus_match,
- .probe = of_device_probe,
- .remove = of_device_remove,
- .suspend = of_device_suspend,
- .resume = of_device_resume,
-};
-
-static int __init of_bus_driver_init(void)
-{
- return bus_register(&of_platform_bus_type);
-}
-
-postcore_initcall(of_bus_driver_init);
-
-int of_register_driver(struct of_platform_driver *drv)
-{
- /* initialize common driver fields */
- drv->driver.name = drv->name;
- drv->driver.bus = &of_platform_bus_type;
-
- /* register with core */
- return driver_register(&drv->driver);
-}
-
-void of_unregister_driver(struct of_platform_driver *drv)
-{
- driver_unregister(&drv->driver);
-}
-
-
-static ssize_t dev_show_devspec(struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t dev_show_devspec(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
struct of_device *ofdev;
@@ -208,41 +121,10 @@ void of_device_unregister(struct of_devi
device_unregister(&ofdev->dev);
}
-struct of_device* of_platform_device_create(struct device_node *np,
- const char *bus_id,
- struct device *parent)
-{
- struct of_device *dev;
-
- dev = kmalloc(sizeof(*dev), GFP_KERNEL);
- if (!dev)
- return NULL;
- memset(dev, 0, sizeof(*dev));
-
- dev->node = of_node_get(np);
- dev->dma_mask = 0xffffffffUL;
- dev->dev.dma_mask = &dev->dma_mask;
- dev->dev.parent = parent;
- dev->dev.bus = &of_platform_bus_type;
- dev->dev.release = of_release_dev;
-
- strlcpy(dev->dev.bus_id, bus_id, BUS_ID_SIZE);
-
- if (of_device_register(dev) != 0) {
- kfree(dev);
- return NULL;
- }
-
- return dev;
-}
EXPORT_SYMBOL(of_match_device);
-EXPORT_SYMBOL(of_platform_bus_type);
-EXPORT_SYMBOL(of_register_driver);
-EXPORT_SYMBOL(of_unregister_driver);
EXPORT_SYMBOL(of_device_register);
EXPORT_SYMBOL(of_device_unregister);
EXPORT_SYMBOL(of_dev_get);
EXPORT_SYMBOL(of_dev_put);
-EXPORT_SYMBOL(of_platform_device_create);
EXPORT_SYMBOL(of_release_dev);
Index: linux-cell/include/asm-powerpc/of_device.h
===================================================================
--- linux-cell.orig/include/asm-powerpc/of_device.h 2006-10-26 17:22:37.000000000 +1000
+++ linux-cell/include/asm-powerpc/of_device.h 2006-10-26 17:40:39.000000000 +1000
@@ -6,12 +6,6 @@
#include <linux/mod_devicetable.h>
#include <asm/prom.h>
-/*
- * The of_platform_bus_type is a bus type used by drivers that do not
- * attach to a macio or similar bus but still use OF probing
- * mechanism
- */
-extern struct bus_type of_platform_bus_type;
/*
* The of_device is a kind of "base class" that is a superset of
@@ -26,40 +20,16 @@ struct of_device
};
#define to_of_device(d) container_of(d, struct of_device, dev)
+extern const struct of_device_id *of_match_node(
+ const struct of_device_id *matches, const struct device_node *node);
extern const struct of_device_id *of_match_device(
const struct of_device_id *matches, const struct of_device *dev);
extern struct of_device *of_dev_get(struct of_device *dev);
extern void of_dev_put(struct of_device *dev);
-/*
- * An of_platform_driver driver is attached to a basic of_device on
- * the "platform bus" (of_platform_bus_type)
- */
-struct of_platform_driver
-{
- char *name;
- struct of_device_id *match_table;
- struct module *owner;
-
- int (*probe)(struct of_device* dev, const struct of_device_id *match);
- int (*remove)(struct of_device* dev);
-
- int (*suspend)(struct of_device* dev, pm_message_t state);
- int (*resume)(struct of_device* dev);
- int (*shutdown)(struct of_device* dev);
-
- struct device_driver driver;
-};
-#define to_of_platform_driver(drv) container_of(drv,struct of_platform_driver, driver)
-
-extern int of_register_driver(struct of_platform_driver *drv);
-extern void of_unregister_driver(struct of_platform_driver *drv);
extern int of_device_register(struct of_device *ofdev);
extern void of_device_unregister(struct of_device *ofdev);
-extern struct of_device *of_platform_device_create(struct device_node *np,
- const char *bus_id,
- struct device *parent);
extern void of_release_dev(struct device *dev);
#endif /* __KERNEL__ */
Index: linux-cell/arch/powerpc/kernel/of_platform.c
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ linux-cell/arch/powerpc/kernel/of_platform.c 2006-10-26 17:40:57.000000000 +1000
@@ -0,0 +1,371 @@
+/*
+ * Copyright (C) 2006 Benjamin Herrenschmidt, IBM Corp.
+ * <benh@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.
+ *
+ */
+
+#undef DEBUG
+
+#include <linux/string.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/mod_devicetable.h>
+#include <linux/slab.h>
+
+#include <asm/errno.h>
+#include <asm/dcr.h>
+#include <asm/of_device.h>
+#include <asm/of_platform.h>
+
+
+/*
+ * The list of OF IDs below is used for matching bus types in the
+ * system whose devices are to be exposed as of_platform_devices.
+ *
+ * This is the default list valid for most platforms. This file provides
+ * functions who can take an explicit list if necessary though
+ *
+ * The search is always performed recursively looking for children of
+ * the provided device_node and recursively if such a children matches
+ * a bus type in the list
+ */
+
+static struct of_device_id of_default_bus_ids[] = {
+ { .type = "soc", },
+ { .compatible = "soc", },
+ { .type = "spider", },
+ { .type = "axon", },
+ { .type = "plb5", },
+ { .type = "plb4", },
+ { .type = "opb", },
+ {},
+};
+
+/*
+ *
+ * OF platform device type definition & base infrastructure
+ *
+ */
+
+static int of_platform_bus_match(struct device *dev, struct device_driver *drv)
+{
+ struct of_device * of_dev = to_of_device(dev);
+ struct of_platform_driver * of_drv = to_of_platform_driver(drv);
+ const struct of_device_id * matches = of_drv->match_table;
+
+ if (!matches)
+ return 0;
+
+ return of_match_device(matches, of_dev) != NULL;
+}
+
+static int of_platform_device_probe(struct device *dev)
+{
+ int error = -ENODEV;
+ struct of_platform_driver *drv;
+ struct of_device *of_dev;
+ const struct of_device_id *match;
+
+ drv = to_of_platform_driver(dev->driver);
+ of_dev = to_of_device(dev);
+
+ if (!drv->probe)
+ return error;
+
+ of_dev_get(of_dev);
+
+ match = of_match_device(drv->match_table, of_dev);
+ if (match)
+ error = drv->probe(of_dev, match);
+ if (error)
+ of_dev_put(of_dev);
+
+ return error;
+}
+
+static int of_platform_device_remove(struct device *dev)
+{
+ struct of_device * of_dev = to_of_device(dev);
+ struct of_platform_driver * drv = to_of_platform_driver(dev->driver);
+
+ if (dev->driver && drv->remove)
+ drv->remove(of_dev);
+ return 0;
+}
+
+static int of_platform_device_suspend(struct device *dev, pm_message_t state)
+{
+ struct of_device * of_dev = to_of_device(dev);
+ struct of_platform_driver * drv = to_of_platform_driver(dev->driver);
+ int error = 0;
+
+ if (dev->driver && drv->suspend)
+ error = drv->suspend(of_dev, state);
+ return error;
+}
+
+static int of_platform_device_resume(struct device * dev)
+{
+ struct of_device * of_dev = to_of_device(dev);
+ struct of_platform_driver * drv = to_of_platform_driver(dev->driver);
+ int error = 0;
+
+ if (dev->driver && drv->resume)
+ error = drv->resume(of_dev);
+ return error;
+}
+
+struct bus_type of_platform_bus_type = {
+ .name = "of_platform",
+ .match = of_platform_bus_match,
+ .probe = of_platform_device_probe,
+ .remove = of_platform_device_remove,
+ .suspend = of_platform_device_suspend,
+ .resume = of_platform_device_resume,
+};
+EXPORT_SYMBOL(of_platform_bus_type);
+
+static int __init of_bus_driver_init(void)
+{
+ return bus_register(&of_platform_bus_type);
+}
+
+postcore_initcall(of_bus_driver_init);
+
+int of_register_platform_driver(struct of_platform_driver *drv)
+{
+ /* initialize common driver fields */
+ drv->driver.name = drv->name;
+ drv->driver.bus = &of_platform_bus_type;
+
+ /* register with core */
+ return driver_register(&drv->driver);
+}
+EXPORT_SYMBOL(of_register_platform_driver);
+
+void of_unregister_platform_driver(struct of_platform_driver *drv)
+{
+ driver_unregister(&drv->driver);
+}
+EXPORT_SYMBOL(of_unregister_platform_driver);
+
+static void of_platform_make_bus_id(struct of_device *dev)
+{
+ struct device_node *node = dev->node;
+ char *name = dev->dev.bus_id;
+ const u32 *reg;
+ u64 addr;
+
+ /*
+ * If it's a DCR based device, use 'd' for native DCRs
+ * and 'D' for MMIO DCRs.
+ */
+#ifdef CONFIG_PPC_DCR
+ reg = get_property(node, "dcr-reg", NULL);
+ if (reg) {
+#ifdef CONFIG_PPC_DCR_NATIVE
+ snprintf(name, BUS_ID_SIZE, "d%x.%s",
+ *reg, node->name);
+#else /* CONFIG_PPC_DCR_NATIVE */
+ addr = of_translate_dcr_address(node, *reg, NULL);
+ if (addr != OF_BAD_ADDR) {
+ snprintf(name, BUS_ID_SIZE,
+ "D%llx.%s", (unsigned long long)addr,
+ node->name);
+ return;
+ }
+#endif /* !CONFIG_PPC_DCR_NATIVE */
+ }
+#endif /* CONFIG_PPC_DCR */
+
+ /*
+ * For MMIO, get the physical address
+ */
+ reg = get_property(node, "reg", NULL);
+ if (reg) {
+ addr = of_translate_address(node, reg);
+ if (addr != OF_BAD_ADDR) {
+ snprintf(name, BUS_ID_SIZE,
+ "%lx.%s", addr, node->name);
+ return;
+ }
+ }
+
+ /*
+ * No BusID, use the node name and pray
+ */
+ snprintf(name, BUS_ID_SIZE, "%s", node->name);
+}
+
+struct of_device* of_platform_device_create(struct device_node *np,
+ const char *bus_id,
+ struct device *parent)
+{
+ struct of_device *dev;
+
+ dev = kmalloc(sizeof(*dev), GFP_KERNEL);
+ if (!dev)
+ return NULL;
+ memset(dev, 0, sizeof(*dev));
+
+ dev->node = of_node_get(np);
+ dev->dma_mask = 0xffffffffUL;
+ dev->dev.dma_mask = &dev->dma_mask;
+ dev->dev.parent = parent;
+ dev->dev.bus = &of_platform_bus_type;
+ dev->dev.release = of_release_dev;
+
+ if (bus_id)
+ strlcpy(dev->dev.bus_id, bus_id, BUS_ID_SIZE);
+ else
+ of_platform_make_bus_id(dev);
+
+ if (of_device_register(dev) != 0) {
+ kfree(dev);
+ return NULL;
+ }
+
+ return dev;
+}
+EXPORT_SYMBOL(of_platform_device_create);
+
+
+
+/**
+ * of_platform_bus_create - Create an OF device for a bus node and all its
+ * children. Optionally recursively instanciate matching busses.
+ * @bus: device node of the bus to instanciate
+ * @matches: match table, NULL to use the default, OF_NO_DEEP_PROBE to
+ * disallow recursive creation of child busses
+ */
+static int of_platform_bus_create(struct device_node *bus,
+ struct of_device_id *matches,
+ struct device *parent)
+{
+ struct device_node *child;
+ struct of_device *dev;
+ int rc = 0;
+
+ for (child = NULL; (child = of_get_next_child(bus, child)); ) {
+ pr_debug(" create child: %s\n", child->full_name);
+ dev = of_platform_device_create(child, NULL, parent);
+ if (dev == NULL)
+ rc = -ENOMEM;
+ else if (!of_match_node(matches, child))
+ continue;
+ if (rc == 0) {
+ pr_debug(" and sub busses\n");
+ rc = of_platform_bus_create(child, matches, &dev->dev);
+ } if (rc) {
+ of_node_put(child);
+ break;
+ }
+ }
+ return rc;
+}
+
+/**
+ * of_platform_bus_probe - Probe the device-tree for platform busses
+ * @root: parent of the first level to probe or NULL for the root of the tree
+ * @matches: match table, NULL to use the default
+ * @parent: parent to hook devices from, NULL for toplevel
+ *
+ * Note that children of the provided root are not instanciated as devices
+ * unless the specified root itself matches the bus list and is not NULL.
+ */
+
+int of_platform_bus_probe(struct device_node *root,
+ struct of_device_id *matches,
+ struct device *parent)
+{
+ struct device_node *child;
+ struct of_device *dev;
+ int rc = 0;
+
+ if (matches == NULL)
+ matches = of_default_bus_ids;
+ if (matches == OF_NO_DEEP_PROBE)
+ return -EINVAL;
+ if (root == NULL)
+ root = of_find_node_by_path("/");
+ else
+ of_node_get(root);
+
+ pr_debug("of_platform_bus_probe()\n");
+ pr_debug(" starting at: %s\n", root->full_name);
+
+ /* Do a self check of bus type, if there's a match, create
+ * children
+ */
+ if (of_match_node(matches, root)) {
+ pr_debug(" root match, create all sub devices\n");
+ dev = of_platform_device_create(root, NULL, parent);
+ if (dev == NULL) {
+ rc = -ENOMEM;
+ goto bail;
+ }
+ pr_debug(" create all sub busses\n");
+ rc = of_platform_bus_create(root, matches, &dev->dev);
+ goto bail;
+ }
+ for (child = NULL; (child = of_get_next_child(root, child)); ) {
+ if (!of_match_node(matches, child))
+ continue;
+
+ pr_debug(" match: %s\n", child->full_name);
+ dev = of_platform_device_create(child, NULL, parent);
+ if (dev == NULL)
+ rc = -ENOMEM;
+ else
+ rc = of_platform_bus_create(child, matches, &dev->dev);
+ if (rc) {
+ of_node_put(child);
+ break;
+ }
+ }
+ bail:
+ of_node_put(root);
+ return rc;
+}
+EXPORT_SYMBOL(of_platform_bus_probe);
+
+static int of_dev_node_match(struct device *dev, void *data)
+{
+ return to_of_device(dev)->node == data;
+}
+
+struct of_device *of_find_device_by_node(struct device_node *np)
+{
+ struct device *dev;
+
+ dev = bus_find_device(&of_platform_bus_type,
+ NULL, np, of_dev_node_match);
+ if (dev)
+ return to_of_device(dev);
+ return NULL;
+}
+EXPORT_SYMBOL(of_find_device_by_node);
+
+static int of_dev_phandle_match(struct device *dev, void *data)
+{
+ phandle *ph = data;
+ return to_of_device(dev)->node->linux_phandle == *ph;
+}
+
+struct of_device *of_find_device_by_phandle(phandle ph)
+{
+ struct device *dev;
+
+ dev = bus_find_device(&of_platform_bus_type,
+ NULL, &ph, of_dev_phandle_match);
+ if (dev)
+ return to_of_device(dev);
+ return NULL;
+}
+EXPORT_SYMBOL(of_find_device_by_phandle);
Index: linux-cell/arch/powerpc/kernel/Makefile
===================================================================
--- linux-cell.orig/arch/powerpc/kernel/Makefile 2006-10-26 17:22:37.000000000 +1000
+++ linux-cell/arch/powerpc/kernel/Makefile 2006-10-26 17:40:39.000000000 +1000
@@ -21,7 +21,7 @@ obj-$(CONFIG_PPC64) += setup_64.o binfm
obj-$(CONFIG_PPC64) += vdso64/
obj-$(CONFIG_ALTIVEC) += vecemu.o vector.o
obj-$(CONFIG_PPC_970_NAP) += idle_power4.o
-obj-$(CONFIG_PPC_OF) += of_device.o prom_parse.o
+obj-$(CONFIG_PPC_OF) += of_device.o of_platform.o prom_parse.o
procfs-$(CONFIG_PPC64) := proc_ppc64.o
obj-$(CONFIG_PROC_FS) += $(procfs-y)
rtaspci-$(CONFIG_PPC64) := rtas_pci.o
Index: linux-cell/drivers/macintosh/therm_pm72.c
===================================================================
--- linux-cell.orig/drivers/macintosh/therm_pm72.c 2006-10-26 17:22:37.000000000 +1000
+++ linux-cell/drivers/macintosh/therm_pm72.c 2006-10-26 17:23:06.000000000 +1000
@@ -129,6 +129,7 @@
#include <asm/sections.h>
#include <asm/of_device.h>
#include <asm/macio.h>
+#include <asm/of_platform.h>
#include "therm_pm72.h"
@@ -2236,14 +2237,14 @@ static int __init therm_pm72_init(void)
return -ENODEV;
}
- of_register_driver(&fcu_of_platform_driver);
+ of_register_platform_driver(&fcu_of_platform_driver);
return 0;
}
static void __exit therm_pm72_exit(void)
{
- of_unregister_driver(&fcu_of_platform_driver);
+ of_unregister_platform_driver(&fcu_of_platform_driver);
if (of_dev)
of_device_unregister(of_dev);
Index: linux-cell/include/asm-powerpc/of_platform.h
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ linux-cell/include/asm-powerpc/of_platform.h 2006-10-26 17:23:06.000000000 +1000
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2006 Benjamin Herrenschmidt, IBM Corp.
+ * <benh@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 <asm/of_device.h>
+
+/*
+ * The of_platform_bus_type is a bus type used by drivers that do not
+ * attach to a macio or similar bus but still use OF probing
+ * mechanism
+ */
+extern struct bus_type of_platform_bus_type;
+
+/*
+ * An of_platform_driver driver is attached to a basic of_device on
+ * the "platform bus" (of_platform_bus_type)
+ */
+struct of_platform_driver
+{
+ char *name;
+ struct of_device_id *match_table;
+ struct module *owner;
+
+ int (*probe)(struct of_device* dev,
+ const struct of_device_id *match);
+ int (*remove)(struct of_device* dev);
+
+ int (*suspend)(struct of_device* dev, pm_message_t state);
+ int (*resume)(struct of_device* dev);
+ int (*shutdown)(struct of_device* dev);
+
+ struct device_driver driver;
+};
+#define to_of_platform_driver(drv) \
+ container_of(drv,struct of_platform_driver, driver)
+
+/* Platform drivers register/unregister */
+extern int of_register_platform_driver(struct of_platform_driver *drv);
+extern void of_unregister_platform_driver(struct of_platform_driver *drv);
+
+/* Platform devices and busses creation */
+extern struct of_device *of_platform_device_create(struct device_node *np,
+ const char *bus_id,
+ struct device *parent);
+/* pseudo "matches" value to not do deep probe */
+#define OF_NO_DEEP_PROBE ((struct of_device_id *)-1)
+
+extern int of_platform_bus_probe(struct device_node *root,
+ struct of_device_id *matches,
+ struct device *parent);
+
+extern struct of_device *of_find_device_by_node(struct device_node *np);
+extern struct of_device *of_find_device_by_phandle(phandle ph);
Index: linux-cell/arch/powerpc/platforms/powermac/setup.c
===================================================================
--- linux-cell.orig/arch/powerpc/platforms/powermac/setup.c 2006-10-26 17:22:37.000000000 +1000
+++ linux-cell/arch/powerpc/platforms/powermac/setup.c 2006-10-26 17:23:06.000000000 +1000
@@ -70,6 +70,7 @@
#include <asm/pmac_feature.h>
#include <asm/time.h>
#include <asm/of_device.h>
+#include <asm/of_platform.h>
#include <asm/mmu_context.h>
#include <asm/iommu.h>
#include <asm/smu.h>
Index: linux-cell/drivers/macintosh/smu.c
===================================================================
--- linux-cell.orig/drivers/macintosh/smu.c 2006-10-26 17:22:37.000000000 +1000
+++ linux-cell/drivers/macintosh/smu.c 2006-10-26 17:23:06.000000000 +1000
@@ -46,6 +46,7 @@
#include <asm/abs_addr.h>
#include <asm/uaccess.h>
#include <asm/of_device.h>
+#include <asm/of_platform.h>
#define VERSION "0.7"
#define AUTHOR "(c) 2005 Benjamin Herrenschmidt, IBM Corp."
@@ -653,7 +654,7 @@ static int __init smu_init_sysfs(void)
* I'm a bit too far from figuring out how that works with those
* new chipsets, but that will come back and bite us
*/
- of_register_driver(&smu_of_platform_driver);
+ of_register_platform_driver(&smu_of_platform_driver);
return 0;
}
Index: linux-cell/drivers/video/platinumfb.c
===================================================================
--- linux-cell.orig/drivers/video/platinumfb.c 2006-10-26 17:22:37.000000000 +1000
+++ linux-cell/drivers/video/platinumfb.c 2006-10-26 17:23:06.000000000 +1000
@@ -34,6 +34,7 @@
#include <asm/prom.h>
#include <asm/pgtable.h>
#include <asm/of_device.h>
+#include <asm/of_platform.h>
#include "macmodes.h"
#include "platinumfb.h"
@@ -682,14 +683,14 @@ static int __init platinumfb_init(void)
return -ENODEV;
platinumfb_setup(option);
#endif
- of_register_driver(&platinum_driver);
+ of_register_platform_driver(&platinum_driver);
return 0;
}
static void __exit platinumfb_exit(void)
{
- of_unregister_driver(&platinum_driver);
+ of_unregister_platform_driver(&platinum_driver);
}
MODULE_LICENSE("GPL");
^ permalink raw reply
* [PATCH/RFC] powerpc: Refactor 64 bits DMA operations
From: Benjamin Herrenschmidt @ 2006-11-03 21:21 UTC (permalink / raw)
To: linuxppc-dev list
This is also something I'll need in 2.6.20. Right now posted only for
comments though. It's known to "miss" fixup of at least pasemi and maybe
a few other things and I've not tested if I break 32 bits build yet :)
This patch completely refactors DMA operations for 64 bits powerpc. 32 bits
is untouched for now.
It depends on the patches previously posted (and now in gregkh tree) to
add a notifier to the bus types for addition/removal of devices.
The basic idea is to define an auxilliary structure (struct device_ext) that
can be attached to any struct device in the system. We use the "firmware_data"
pointer to reference it for now, though I kept that very isolated so I can
change it in the future, especially if I get my way with Greg KH and add a
sysdata pointer to struct device instead or even better, embed it inside
struct device to limit the number of pointer indirections.
This structure holds the optional OF device node pointer, the DMA ops and
associated void *data (to be used by the ops, typically, the iommu table
pointer for machines with more than one), and a numa node id (if useful)
to constraint consistent memory allocs. In the future, I might also merge
the current pci_dn into it for PCI.
The old vio, pci-iommu and pci-direct DMA ops are gone. They are now replaced
by a set of generic iommu and direct DMA ops (non PCI specific) that can be
used by bus types. The toplevel implementation is now inline.
In the case of busses we control completely, like vio, the bus layer will
create and fill this structure and all is easy (see the changes to vio.c
or ebus).
In the case of "foreign" busses like PCI, what I've done is that I create
the data structure in the PCI fixup code (which is run after discovery but
before the struct device is actually registered with the core, as PCI keeps
those two steps separate) and use the old ppc_md. callbacks that I renamed
for consistency, to setup the iommu table pointer if necessary. By default
the dma_ops are set to the content of a global pci_dma_ops that your platform
can set. So if you have no iommu, you can just set that dma_direct_ops and
not implement any of the callbacks.
I do have plans to move away from that model for PCI, and consolidate this
with pci_dn, while make everybody use the platform notifiers provided by
the device core upon device registration but this goes beyond the goal of
this patch.
The cool thing is that the diffstat is also negative:
arch/powerpc/kernel/pci_direct_iommu.c | 98 -------
arch/powerpc/kernel/pci_iommu.c | 164 -----------
linux-cell/arch/powerpc/kernel/Makefile | 3
linux-cell/arch/powerpc/kernel/dma_64.c | 251 ++++++++++--------
linux-cell/arch/powerpc/kernel/ibmebus.c | 6
linux-cell/arch/powerpc/kernel/iommu.c | 6
linux-cell/arch/powerpc/kernel/of_platform.c | 10
linux-cell/arch/powerpc/kernel/pci_64.c | 56 +++-
linux-cell/arch/powerpc/kernel/setup_64.c | 5
linux-cell/arch/powerpc/kernel/vio.c | 103 ++-----
linux-cell/arch/powerpc/platforms/cell/iommu.c | 21 -
linux-cell/arch/powerpc/platforms/iseries/iommu.c | 20 -
linux-cell/arch/powerpc/platforms/iseries/pci.c | 2
linux-cell/arch/powerpc/platforms/pseries/iommu.c | 105 ++++---
linux-cell/arch/powerpc/platforms/pseries/pci_dlpar.c | 4
linux-cell/arch/powerpc/sysdev/dart_iommu.c | 38 +-
linux-cell/include/asm-powerpc/device_ext.h | 43 +++
linux-cell/include/asm-powerpc/dma-mapping.h | 185 ++++++++++---
linux-cell/include/asm-powerpc/ibmebus.h | 3
linux-cell/include/asm-powerpc/iommu.h | 20 -
linux-cell/include/asm-powerpc/iseries/iommu.h | 4
linux-cell/include/asm-powerpc/machdep.h | 4
linux-cell/include/asm-powerpc/of_device.h | 4
linux-cell/include/asm-powerpc/pci-bridge.h | 3
linux-cell/include/asm-powerpc/pci.h | 8
linux-cell/include/asm-powerpc/vio.h | 3
26 files changed, 577 insertions(+), 592 deletions(-)
Index: linux-cell/include/asm-powerpc/device_ext.h
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ linux-cell/include/asm-powerpc/device_ext.h 2006-11-02 13:27:24.000000000 +1100
@@ -0,0 +1,43 @@
+#ifndef _POWERPC_DEVICE_EXT_H
+#define _POWERPC_DEVICE_EXT_H
+#ifdef __KERNEL__
+
+struct dma_mapping_ops;
+struct device_node;
+
+/*
+ * Auxilliary data structure that can be attached to any struct device
+ * in the system. (Currently using firmware_data, though I'd like to
+ * see a system_data in there instead).
+ *
+ * The structure can be wrapped within a bus-type specific data structure.
+ *
+ * There are no strict lifetime rules for this structure, it's entirely up
+ * to the bus to manage it's lifetime.
+ */
+struct device_ext {
+ /* Optional pointer to an OF device node */
+ struct device_node *of_node;
+
+ /* DMA operations on that device */
+ struct dma_mapping_ops *dma_ops;
+ void *dma_data;
+
+ /* NUMA node if applicable */
+ int numa_node;
+};
+
+/* Provide accessors in case we move it to some other field */
+static inline struct device_ext *device_get_ext(const struct device *dev)
+{
+ return dev->firmware_data;
+}
+
+static inline void device_set_ext(struct device *dev, struct device_ext *ext)
+{
+ dev->firmware_data = ext;
+}
+
+
+#endif /* __KERNEL__ */
+#endif /* _POWERPC_DEVICE_EXT_H */
Index: linux-cell/arch/powerpc/kernel/dma_64.c
===================================================================
--- linux-cell.orig/arch/powerpc/kernel/dma_64.c 2006-11-02 13:22:04.000000000 +1100
+++ linux-cell/arch/powerpc/kernel/dma_64.c 2006-11-02 13:27:24.000000000 +1100
@@ -1,151 +1,204 @@
/*
- * Copyright (C) 2004 IBM Corporation
+ * Copyright (C) 2006 Benjamin Herrenschmidt, IBM Corporation
*
- * Implements the generic device dma API for ppc64. Handles
- * the pci and vio busses
+ * Provide default implementations of the DMA mapping callbacks for
+ * directly mapped busses and busses using the iommu infrastructure
*/
#include <linux/device.h>
#include <linux/dma-mapping.h>
-/* Include the busses we support */
-#include <linux/pci.h>
-#include <asm/vio.h>
-#include <asm/ibmebus.h>
-#include <asm/scatterlist.h>
#include <asm/bug.h>
+#include <asm/iommu.h>
+#include <asm/abs_addr.h>
-static struct dma_mapping_ops *get_dma_ops(struct device *dev)
+/*
+ * Generic iommu implementation
+ */
+
+static inline unsigned long device_to_mask(struct device *dev)
{
-#ifdef CONFIG_PCI
- if (dev->bus == &pci_bus_type)
- return &pci_dma_ops;
-#endif
-#ifdef CONFIG_IBMVIO
- if (dev->bus == &vio_bus_type)
- return &vio_dma_ops;
-#endif
-#ifdef CONFIG_IBMEBUS
- if (dev->bus == &ibmebus_bus_type)
- return &ibmebus_dma_ops;
-#endif
- return NULL;
+ if (dev->dma_mask && *dev->dma_mask)
+ return *dev->dma_mask;
+ /* Assume devices without mask can take 32 bit addresses */
+ return 0xfffffffful;
}
-int dma_supported(struct device *dev, u64 mask)
-{
- struct dma_mapping_ops *dma_ops = get_dma_ops(dev);
- BUG_ON(!dma_ops);
+/* Allocates a contiguous real buffer and creates mappings over it.
+ * Returns the virtual address of the buffer and sets dma_handle
+ * to the dma address (mapping) of the first page.
+ */
+static void *dma_iommu_alloc_coherent(struct device *dev, size_t size,
+ dma_addr_t *dma_handle, gfp_t flag)
+{
+ struct device_ext *dext = device_get_ext(dev);
- return dma_ops->dma_supported(dev, mask);
+ if (unlikely(dext == NULL))
+ return NULL;
+ return iommu_alloc_coherent(dext->dma_data, size, dma_handle,
+ device_to_mask(dev), flag,
+ dext->numa_node);
}
-EXPORT_SYMBOL(dma_supported);
-int dma_set_mask(struct device *dev, u64 dma_mask)
+static void dma_iommu_free_coherent(struct device *dev, size_t size,
+ void *vaddr, dma_addr_t dma_handle)
{
-#ifdef CONFIG_PCI
- if (dev->bus == &pci_bus_type)
- return pci_set_dma_mask(to_pci_dev(dev), dma_mask);
-#endif
-#ifdef CONFIG_IBMVIO
- if (dev->bus == &vio_bus_type)
- return -EIO;
-#endif /* CONFIG_IBMVIO */
-#ifdef CONFIG_IBMEBUS
- if (dev->bus == &ibmebus_bus_type)
- return -EIO;
-#endif
- BUG();
- return 0;
+ struct device_ext *dext = device_get_ext(dev);
+
+ if (unlikely(dext == NULL))
+ return;
+ iommu_free_coherent(dext->dma_data, size, vaddr, dma_handle);
}
-EXPORT_SYMBOL(dma_set_mask);
-void *dma_alloc_coherent(struct device *dev, size_t size,
- dma_addr_t *dma_handle, gfp_t flag)
+/* Creates TCEs for a user provided buffer. The user buffer must be
+ * contiguous real kernel storage (not vmalloc). The address of the buffer
+ * passed here is the kernel (virtual) address of the buffer. The buffer
+ * need not be page aligned, the dma_addr_t returned will point to the same
+ * byte within the page as vaddr.
+ */
+static dma_addr_t dma_iommu_map_single(struct device *dev, void *vaddr,
+ size_t size,
+ enum dma_data_direction direction)
{
- struct dma_mapping_ops *dma_ops = get_dma_ops(dev);
+ struct device_ext *dext = device_get_ext(dev);
- BUG_ON(!dma_ops);
-
- return dma_ops->alloc_coherent(dev, size, dma_handle, flag);
+ if (unlikely(dext == NULL))
+ return DMA_ERROR_CODE;
+ return iommu_map_single(dext->dma_data, vaddr, size,
+ device_to_mask(dev), direction);
}
-EXPORT_SYMBOL(dma_alloc_coherent);
-void dma_free_coherent(struct device *dev, size_t size, void *cpu_addr,
- dma_addr_t dma_handle)
-{
- struct dma_mapping_ops *dma_ops = get_dma_ops(dev);
- BUG_ON(!dma_ops);
+static void dma_iommu_unmap_single(struct device *dev, dma_addr_t dma_handle,
+ size_t size,
+ enum dma_data_direction direction)
+{
+ struct device_ext *dext = device_get_ext(dev);
- dma_ops->free_coherent(dev, size, cpu_addr, dma_handle);
+ if (unlikely(dext == NULL))
+ return;
+ iommu_unmap_single(dext->dma_data, dma_handle, size, direction);
}
-EXPORT_SYMBOL(dma_free_coherent);
-dma_addr_t dma_map_single(struct device *dev, void *cpu_addr, size_t size,
- enum dma_data_direction direction)
-{
- struct dma_mapping_ops *dma_ops = get_dma_ops(dev);
- BUG_ON(!dma_ops);
+static int dma_iommu_map_sg(struct device *dev, struct scatterlist *sglist,
+ int nelems, enum dma_data_direction direction)
+{
+ struct device_ext *dext = device_get_ext(dev);
- return dma_ops->map_single(dev, cpu_addr, size, direction);
+ if (unlikely(dext == NULL))
+ return -ENXIO;
+ return iommu_map_sg(dext->dma_data, sglist, nelems,
+ device_to_mask(dev), direction);
}
-EXPORT_SYMBOL(dma_map_single);
-void dma_unmap_single(struct device *dev, dma_addr_t dma_addr, size_t size,
- enum dma_data_direction direction)
+static void dma_iommu_unmap_sg(struct device *dev, struct scatterlist *sglist,
+ int nelems, enum dma_data_direction direction)
{
- struct dma_mapping_ops *dma_ops = get_dma_ops(dev);
-
- BUG_ON(!dma_ops);
+ struct device_ext *dext = device_get_ext(dev);
- dma_ops->unmap_single(dev, dma_addr, size, direction);
+ if (unlikely(dext == NULL))
+ return;
+ iommu_unmap_sg(dext->dma_data, sglist, nelems, direction);
}
-EXPORT_SYMBOL(dma_unmap_single);
-dma_addr_t dma_map_page(struct device *dev, struct page *page,
- unsigned long offset, size_t size,
- enum dma_data_direction direction)
+/* We support DMA to/from any memory page via the iommu */
+static int dma_iommu_dma_supported(struct device *dev, u64 mask)
{
- struct dma_mapping_ops *dma_ops = get_dma_ops(dev);
+ struct device_ext *dext = device_get_ext(dev);
+ struct iommu_table *tbl = dext->dma_data;
- BUG_ON(!dma_ops);
+ if (!tbl || tbl->it_offset > mask) {
+ printk(KERN_INFO "Warning: IOMMU table offset too big for device mask\n");
+ if (tbl)
+ printk(KERN_INFO "mask: 0x%08lx, table offset: 0x%08lx\n",
+ mask, tbl->it_offset);
+ else
+ printk(KERN_INFO "mask: 0x%08lx, table unavailable\n",
+ mask);
+ return 0;
+ } else
+ return 1;
+}
- return dma_ops->map_single(dev, page_address(page) + offset, size,
- direction);
+struct dma_mapping_ops dma_iommu_ops = {
+ .alloc_coherent = dma_iommu_alloc_coherent,
+ .free_coherent = dma_iommu_free_coherent,
+ .map_single = dma_iommu_map_single,
+ .unmap_single = dma_iommu_unmap_single,
+ .map_sg = dma_iommu_map_sg,
+ .unmap_sg = dma_iommu_unmap_sg,
+ .dma_supported = dma_iommu_dma_supported,
+};
+EXPORT_SYMBOL(dma_iommu_ops);
+
+/*
+ * Generic direct DMA implementation
+ */
+
+static void *dma_direct_alloc_coherent(struct device *dev, size_t size,
+ dma_addr_t *dma_handle, gfp_t flag)
+{
+ void *ret;
+
+ /* TODO: Maybe use the numa node here too ? */
+ ret = (void *)__get_free_pages(flag, get_order(size));
+ if (ret != NULL) {
+ memset(ret, 0, size);
+ *dma_handle = virt_to_abs(ret);
+ }
+ return ret;
}
-EXPORT_SYMBOL(dma_map_page);
-void dma_unmap_page(struct device *dev, dma_addr_t dma_address, size_t size,
- enum dma_data_direction direction)
+static void dma_direct_free_coherent(struct device *dev, size_t size,
+ void *vaddr, dma_addr_t dma_handle)
{
- struct dma_mapping_ops *dma_ops = get_dma_ops(dev);
+ free_pages((unsigned long)vaddr, get_order(size));
+}
- BUG_ON(!dma_ops);
+static dma_addr_t dma_direct_map_single(struct device *dev, void *ptr,
+ size_t size,
+ enum dma_data_direction direction)
+{
+ return virt_to_abs(ptr);
+}
- dma_ops->unmap_single(dev, dma_address, size, direction);
+static void dma_direct_unmap_single(struct device *dev, dma_addr_t dma_addr,
+ size_t size,
+ enum dma_data_direction direction)
+{
}
-EXPORT_SYMBOL(dma_unmap_page);
-int dma_map_sg(struct device *dev, struct scatterlist *sg, int nents,
- enum dma_data_direction direction)
+static int dma_direct_map_sg(struct device *dev, struct scatterlist *sg,
+ int nents, enum dma_data_direction direction)
{
- struct dma_mapping_ops *dma_ops = get_dma_ops(dev);
+ int i;
- BUG_ON(!dma_ops);
+ for (i = 0; i < nents; i++, sg++) {
+ sg->dma_address = page_to_phys(sg->page) + sg->offset;
+ sg->dma_length = sg->length;
+ }
- return dma_ops->map_sg(dev, sg, nents, direction);
+ return nents;
}
-EXPORT_SYMBOL(dma_map_sg);
-void dma_unmap_sg(struct device *dev, struct scatterlist *sg, int nhwentries,
- enum dma_data_direction direction)
+static void dma_direct_unmap_sg(struct device *dev, struct scatterlist *sg,
+ int nents, enum dma_data_direction direction)
{
- struct dma_mapping_ops *dma_ops = get_dma_ops(dev);
-
- BUG_ON(!dma_ops);
+}
- dma_ops->unmap_sg(dev, sg, nhwentries, direction);
+static int dma_direct_dma_supported(struct device *dev, u64 mask)
+{
+ return mask < 0x100000000ull;
}
-EXPORT_SYMBOL(dma_unmap_sg);
+
+struct dma_mapping_ops dma_direct_ops = {
+ .alloc_coherent = dma_direct_alloc_coherent,
+ .free_coherent = dma_direct_free_coherent,
+ .map_single = dma_direct_map_single,
+ .unmap_single = dma_direct_unmap_single,
+ .map_sg = dma_direct_map_sg,
+ .unmap_sg = dma_direct_unmap_sg,
+ .dma_supported = dma_direct_dma_supported,
+};
+EXPORT_SYMBOL(dma_direct_ops);
Index: linux-cell/arch/powerpc/kernel/iommu.c
===================================================================
--- linux-cell.orig/arch/powerpc/kernel/iommu.c 2006-11-02 13:22:04.000000000 +1100
+++ linux-cell/arch/powerpc/kernel/iommu.c 2006-11-03 12:56:26.000000000 +1100
@@ -258,9 +258,9 @@ static void iommu_free(struct iommu_tabl
spin_unlock_irqrestore(&(tbl->it_lock), flags);
}
-int iommu_map_sg(struct device *dev, struct iommu_table *tbl,
- struct scatterlist *sglist, int nelems,
- unsigned long mask, enum dma_data_direction direction)
+int iommu_map_sg(struct iommu_table *tbl, struct scatterlist *sglist,
+ int nelems, unsigned long mask,
+ enum dma_data_direction direction)
{
dma_addr_t dma_next = 0, dma_addr;
unsigned long flags;
Index: linux-cell/arch/powerpc/kernel/pci_direct_iommu.c
===================================================================
--- linux-cell.orig/arch/powerpc/kernel/pci_direct_iommu.c 2006-11-02 13:22:04.000000000 +1100
+++ /dev/null 1970-01-01 00:00:00.000000000 +0000
@@ -1,98 +0,0 @@
-/*
- * Support for DMA from PCI devices to main memory on
- * machines without an iommu or with directly addressable
- * RAM (typically a pmac with 2Gb of RAM or less)
- *
- * Copyright (C) 2003 Benjamin Herrenschmidt (benh@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/kernel.h>
-#include <linux/pci.h>
-#include <linux/delay.h>
-#include <linux/string.h>
-#include <linux/init.h>
-#include <linux/bootmem.h>
-#include <linux/mm.h>
-#include <linux/dma-mapping.h>
-
-#include <asm/sections.h>
-#include <asm/io.h>
-#include <asm/prom.h>
-#include <asm/pci-bridge.h>
-#include <asm/machdep.h>
-#include <asm/pmac_feature.h>
-#include <asm/abs_addr.h>
-#include <asm/ppc-pci.h>
-
-static void *pci_direct_alloc_coherent(struct device *hwdev, size_t size,
- dma_addr_t *dma_handle, gfp_t flag)
-{
- void *ret;
-
- ret = (void *)__get_free_pages(flag, get_order(size));
- if (ret != NULL) {
- memset(ret, 0, size);
- *dma_handle = virt_to_abs(ret);
- }
- return ret;
-}
-
-static void pci_direct_free_coherent(struct device *hwdev, size_t size,
- void *vaddr, dma_addr_t dma_handle)
-{
- free_pages((unsigned long)vaddr, get_order(size));
-}
-
-static dma_addr_t pci_direct_map_single(struct device *hwdev, void *ptr,
- size_t size, enum dma_data_direction direction)
-{
- return virt_to_abs(ptr);
-}
-
-static void pci_direct_unmap_single(struct device *hwdev, dma_addr_t dma_addr,
- size_t size, enum dma_data_direction direction)
-{
-}
-
-static int pci_direct_map_sg(struct device *hwdev, struct scatterlist *sg,
- int nents, enum dma_data_direction direction)
-{
- int i;
-
- for (i = 0; i < nents; i++, sg++) {
- sg->dma_address = page_to_phys(sg->page) + sg->offset;
- sg->dma_length = sg->length;
- }
-
- return nents;
-}
-
-static void pci_direct_unmap_sg(struct device *hwdev, struct scatterlist *sg,
- int nents, enum dma_data_direction direction)
-{
-}
-
-static int pci_direct_dma_supported(struct device *dev, u64 mask)
-{
- return mask < 0x100000000ull;
-}
-
-static struct dma_mapping_ops pci_direct_ops = {
- .alloc_coherent = pci_direct_alloc_coherent,
- .free_coherent = pci_direct_free_coherent,
- .map_single = pci_direct_map_single,
- .unmap_single = pci_direct_unmap_single,
- .map_sg = pci_direct_map_sg,
- .unmap_sg = pci_direct_unmap_sg,
- .dma_supported = pci_direct_dma_supported,
-};
-
-void __init pci_direct_iommu_init(void)
-{
- pci_dma_ops = pci_direct_ops;
-}
Index: linux-cell/arch/powerpc/kernel/pci_iommu.c
===================================================================
--- linux-cell.orig/arch/powerpc/kernel/pci_iommu.c 2006-11-02 13:22:04.000000000 +1100
+++ /dev/null 1970-01-01 00:00:00.000000000 +0000
@@ -1,164 +0,0 @@
-/*
- * Copyright (C) 2001 Mike Corrigan & Dave Engebretsen, IBM Corporation
- *
- * Rewrite, cleanup, new allocation schemes:
- * Copyright (C) 2004 Olof Johansson, IBM Corporation
- *
- * Dynamic DMA mapping support, platform-independent parts.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-
-#include <linux/init.h>
-#include <linux/types.h>
-#include <linux/slab.h>
-#include <linux/mm.h>
-#include <linux/spinlock.h>
-#include <linux/string.h>
-#include <linux/pci.h>
-#include <linux/dma-mapping.h>
-#include <asm/io.h>
-#include <asm/prom.h>
-#include <asm/iommu.h>
-#include <asm/pci-bridge.h>
-#include <asm/machdep.h>
-#include <asm/ppc-pci.h>
-
-/*
- * We can use ->sysdata directly and avoid the extra work in
- * pci_device_to_OF_node since ->sysdata will have been initialised
- * in the iommu init code for all devices.
- */
-#define PCI_GET_DN(dev) ((struct device_node *)((dev)->sysdata))
-
-static inline struct iommu_table *device_to_table(struct device *hwdev)
-{
- struct pci_dev *pdev;
-
- if (!hwdev) {
- pdev = ppc64_isabridge_dev;
- if (!pdev)
- return NULL;
- } else
- pdev = to_pci_dev(hwdev);
-
- return PCI_DN(PCI_GET_DN(pdev))->iommu_table;
-}
-
-
-static inline unsigned long device_to_mask(struct device *hwdev)
-{
- struct pci_dev *pdev;
-
- if (!hwdev) {
- pdev = ppc64_isabridge_dev;
- if (!pdev) /* This is the best guess we can do */
- return 0xfffffffful;
- } else
- pdev = to_pci_dev(hwdev);
-
- if (pdev->dma_mask)
- return pdev->dma_mask;
-
- /* Assume devices without mask can take 32 bit addresses */
- return 0xfffffffful;
-}
-
-
-/* Allocates a contiguous real buffer and creates mappings over it.
- * Returns the virtual address of the buffer and sets dma_handle
- * to the dma address (mapping) of the first page.
- */
-static void *pci_iommu_alloc_coherent(struct device *hwdev, size_t size,
- dma_addr_t *dma_handle, gfp_t flag)
-{
- return iommu_alloc_coherent(device_to_table(hwdev), size, dma_handle,
- device_to_mask(hwdev), flag,
- pcibus_to_node(to_pci_dev(hwdev)->bus));
-}
-
-static void pci_iommu_free_coherent(struct device *hwdev, size_t size,
- void *vaddr, dma_addr_t dma_handle)
-{
- iommu_free_coherent(device_to_table(hwdev), size, vaddr, dma_handle);
-}
-
-/* Creates TCEs for a user provided buffer. The user buffer must be
- * contiguous real kernel storage (not vmalloc). The address of the buffer
- * passed here is the kernel (virtual) address of the buffer. The buffer
- * need not be page aligned, the dma_addr_t returned will point to the same
- * byte within the page as vaddr.
- */
-static dma_addr_t pci_iommu_map_single(struct device *hwdev, void *vaddr,
- size_t size, enum dma_data_direction direction)
-{
- return iommu_map_single(device_to_table(hwdev), vaddr, size,
- device_to_mask(hwdev), direction);
-}
-
-
-static void pci_iommu_unmap_single(struct device *hwdev, dma_addr_t dma_handle,
- size_t size, enum dma_data_direction direction)
-{
- iommu_unmap_single(device_to_table(hwdev), dma_handle, size, direction);
-}
-
-
-static int pci_iommu_map_sg(struct device *pdev, struct scatterlist *sglist,
- int nelems, enum dma_data_direction direction)
-{
- return iommu_map_sg(pdev, device_to_table(pdev), sglist,
- nelems, device_to_mask(pdev), direction);
-}
-
-static void pci_iommu_unmap_sg(struct device *pdev, struct scatterlist *sglist,
- int nelems, enum dma_data_direction direction)
-{
- iommu_unmap_sg(device_to_table(pdev), sglist, nelems, direction);
-}
-
-/* We support DMA to/from any memory page via the iommu */
-static int pci_iommu_dma_supported(struct device *dev, u64 mask)
-{
- struct iommu_table *tbl = device_to_table(dev);
-
- if (!tbl || tbl->it_offset > mask) {
- printk(KERN_INFO "Warning: IOMMU table offset too big for device mask\n");
- if (tbl)
- printk(KERN_INFO "mask: 0x%08lx, table offset: 0x%08lx\n",
- mask, tbl->it_offset);
- else
- printk(KERN_INFO "mask: 0x%08lx, table unavailable\n",
- mask);
- return 0;
- } else
- return 1;
-}
-
-struct dma_mapping_ops pci_iommu_ops = {
- .alloc_coherent = pci_iommu_alloc_coherent,
- .free_coherent = pci_iommu_free_coherent,
- .map_single = pci_iommu_map_single,
- .unmap_single = pci_iommu_unmap_single,
- .map_sg = pci_iommu_map_sg,
- .unmap_sg = pci_iommu_unmap_sg,
- .dma_supported = pci_iommu_dma_supported,
-};
-
-void pci_iommu_init(void)
-{
- pci_dma_ops = pci_iommu_ops;
-}
Index: linux-cell/include/asm-powerpc/dma-mapping.h
===================================================================
--- linux-cell.orig/include/asm-powerpc/dma-mapping.h 2006-11-02 13:22:04.000000000 +1100
+++ linux-cell/include/asm-powerpc/dma-mapping.h 2006-11-02 13:48:33.000000000 +1100
@@ -14,6 +14,7 @@
#include <linux/mm.h>
#include <asm/scatterlist.h>
#include <asm/io.h>
+#include <asm/device_ext.h>
#define DMA_ERROR_CODE (~(dma_addr_t)0x0)
@@ -44,26 +45,152 @@ extern void __dma_sync_page(struct page
#endif /* ! CONFIG_NOT_COHERENT_CACHE */
#ifdef CONFIG_PPC64
+/*
+ * DMA operations are abstracted for G5 vs. i/pSeries, PCI vs. VIO
+ */
+struct dma_mapping_ops {
+ void * (*alloc_coherent)(struct device *dev, size_t size,
+ dma_addr_t *dma_handle, gfp_t flag);
+ void (*free_coherent)(struct device *dev, size_t size,
+ void *vaddr, dma_addr_t dma_handle);
+ dma_addr_t (*map_single)(struct device *dev, void *ptr,
+ size_t size, enum dma_data_direction direction);
+ void (*unmap_single)(struct device *dev, dma_addr_t dma_addr,
+ size_t size, enum dma_data_direction direction);
+ int (*map_sg)(struct device *dev, struct scatterlist *sg,
+ int nents, enum dma_data_direction direction);
+ void (*unmap_sg)(struct device *dev, struct scatterlist *sg,
+ int nents, enum dma_data_direction direction);
+ int (*dma_supported)(struct device *dev, u64 mask);
+ int (*dac_dma_supported)(struct device *dev, u64 mask);
+ int (*set_dma_mask)(struct device *dev, u64 dma_mask);
+};
+
+static inline struct dma_mapping_ops *get_dma_ops(struct device *dev)
+{
+ struct device_ext *dext;
+
+ /* We don't handle the NULL dev case for ISA for now. We could
+ * do it via an out of line call but it is not needed for now
+ */
+ if (dev == NULL)
+ return NULL;
+
+ dext = device_get_ext(dev);
+ if (unlikely(dext == NULL))
+ return NULL;
+ return dext->dma_ops;
+}
+
+static inline int dma_supported(struct device *dev, u64 mask)
+{
+ struct dma_mapping_ops *dma_ops = get_dma_ops(dev);
+
+ if (unlikely(dma_ops == NULL))
+ return 0;
+ if (dma_ops->dma_supported == NULL)
+ return 1;
+ return dma_ops->dma_supported(dev, mask);
+}
+
+static inline int dma_set_mask(struct device *dev, u64 dma_mask)
+{
+ struct dma_mapping_ops *dma_ops = get_dma_ops(dev);
+
+ if (unlikely(dma_ops == NULL))
+ return -EIO;
+ if (dma_ops->set_dma_mask != NULL)
+ return dma_ops->set_dma_mask(dev, dma_mask);
+ if (!dev->dma_mask || !dma_supported(dev, *dev->dma_mask))
+ return -EIO;
+ *dev->dma_mask = dma_mask;
+ return 0;
+}
+
+static inline void *dma_alloc_coherent(struct device *dev, size_t size,
+ dma_addr_t *dma_handle, gfp_t flag)
+{
+ struct dma_mapping_ops *dma_ops = get_dma_ops(dev);
+
+ BUG_ON(!dma_ops);
+ return dma_ops->alloc_coherent(dev, size, dma_handle, flag);
+}
+
+static inline void dma_free_coherent(struct device *dev, size_t size,
+ void *cpu_addr, dma_addr_t dma_handle)
+{
+ struct dma_mapping_ops *dma_ops = get_dma_ops(dev);
+
+ BUG_ON(!dma_ops);
+ dma_ops->free_coherent(dev, size, cpu_addr, dma_handle);
+}
+
+static inline dma_addr_t dma_map_single(struct device *dev, void *cpu_addr,
+ size_t size,
+ enum dma_data_direction direction)
+{
+ struct dma_mapping_ops *dma_ops = get_dma_ops(dev);
+
+ BUG_ON(!dma_ops);
+ return dma_ops->map_single(dev, cpu_addr, size, direction);
+}
+
+static inline void dma_unmap_single(struct device *dev, dma_addr_t dma_addr,
+ size_t size,
+ enum dma_data_direction direction)
+{
+ struct dma_mapping_ops *dma_ops = get_dma_ops(dev);
+
+ BUG_ON(!dma_ops);
+ dma_ops->unmap_single(dev, dma_addr, size, direction);
+}
+
+static inline dma_addr_t dma_map_page(struct device *dev, struct page *page,
+ unsigned long offset, size_t size,
+ enum dma_data_direction direction)
+{
+ struct dma_mapping_ops *dma_ops = get_dma_ops(dev);
+
+ BUG_ON(!dma_ops);
+ return dma_ops->map_single(dev, page_address(page) + offset, size,
+ direction);
+}
+
+static inline void dma_unmap_page(struct device *dev, dma_addr_t dma_address,
+ size_t size,
+ enum dma_data_direction direction)
+{
+ struct dma_mapping_ops *dma_ops = get_dma_ops(dev);
+
+ BUG_ON(!dma_ops);
+ dma_ops->unmap_single(dev, dma_address, size, direction);
+}
+
+static inline int dma_map_sg(struct device *dev, struct scatterlist *sg,
+ int nents, enum dma_data_direction direction)
+{
+ struct dma_mapping_ops *dma_ops = get_dma_ops(dev);
+
+ BUG_ON(!dma_ops);
+ return dma_ops->map_sg(dev, sg, nents, direction);
+}
+
+static inline void dma_unmap_sg(struct device *dev, struct scatterlist *sg,
+ int nhwentries,
+ enum dma_data_direction direction)
+{
+ struct dma_mapping_ops *dma_ops = get_dma_ops(dev);
+
+ BUG_ON(!dma_ops);
+ dma_ops->unmap_sg(dev, sg, nhwentries, direction);
+}
-extern int dma_supported(struct device *dev, u64 mask);
-extern int dma_set_mask(struct device *dev, u64 dma_mask);
-extern void *dma_alloc_coherent(struct device *dev, size_t size,
- dma_addr_t *dma_handle, gfp_t flag);
-extern void dma_free_coherent(struct device *dev, size_t size, void *cpu_addr,
- dma_addr_t dma_handle);
-extern dma_addr_t dma_map_single(struct device *dev, void *cpu_addr,
- size_t size, enum dma_data_direction direction);
-extern void dma_unmap_single(struct device *dev, dma_addr_t dma_addr,
- size_t size, enum dma_data_direction direction);
-extern dma_addr_t dma_map_page(struct device *dev, struct page *page,
- unsigned long offset, size_t size,
- enum dma_data_direction direction);
-extern void dma_unmap_page(struct device *dev, dma_addr_t dma_address,
- size_t size, enum dma_data_direction direction);
-extern int dma_map_sg(struct device *dev, struct scatterlist *sg, int nents,
- enum dma_data_direction direction);
-extern void dma_unmap_sg(struct device *dev, struct scatterlist *sg,
- int nhwentries, enum dma_data_direction direction);
+
+/*
+ * Available generic sets of operations
+ */
+extern struct dma_mapping_ops dma_iommu_ops;
+extern struct dma_mapping_ops dma_direct_ops;
#else /* CONFIG_PPC64 */
@@ -261,25 +388,5 @@ static inline void dma_cache_sync(void *
__dma_sync(vaddr, size, (int)direction);
}
-/*
- * DMA operations are abstracted for G5 vs. i/pSeries, PCI vs. VIO
- */
-struct dma_mapping_ops {
- void * (*alloc_coherent)(struct device *dev, size_t size,
- dma_addr_t *dma_handle, gfp_t flag);
- void (*free_coherent)(struct device *dev, size_t size,
- void *vaddr, dma_addr_t dma_handle);
- dma_addr_t (*map_single)(struct device *dev, void *ptr,
- size_t size, enum dma_data_direction direction);
- void (*unmap_single)(struct device *dev, dma_addr_t dma_addr,
- size_t size, enum dma_data_direction direction);
- int (*map_sg)(struct device *dev, struct scatterlist *sg,
- int nents, enum dma_data_direction direction);
- void (*unmap_sg)(struct device *dev, struct scatterlist *sg,
- int nents, enum dma_data_direction direction);
- int (*dma_supported)(struct device *dev, u64 mask);
- int (*dac_dma_supported)(struct device *dev, u64 mask);
-};
-
#endif /* __KERNEL__ */
#endif /* _ASM_DMA_MAPPING_H */
Index: linux-cell/include/asm-powerpc/iommu.h
===================================================================
--- linux-cell.orig/include/asm-powerpc/iommu.h 2006-11-02 13:22:04.000000000 +1100
+++ linux-cell/include/asm-powerpc/iommu.h 2006-11-02 13:27:24.000000000 +1100
@@ -87,22 +87,22 @@ extern void iommu_free_table(struct devi
extern struct iommu_table *iommu_init_table(struct iommu_table * tbl,
int nid);
-extern int iommu_map_sg(struct device *dev, struct iommu_table *tbl,
- struct scatterlist *sglist, int nelems, unsigned long mask,
- enum dma_data_direction direction);
+extern int iommu_map_sg(struct iommu_table *tbl, struct scatterlist *sglist,
+ int nelems, unsigned long mask,
+ enum dma_data_direction direction);
extern void iommu_unmap_sg(struct iommu_table *tbl, struct scatterlist *sglist,
- int nelems, enum dma_data_direction direction);
+ int nelems, enum dma_data_direction direction);
extern void *iommu_alloc_coherent(struct iommu_table *tbl, size_t size,
- dma_addr_t *dma_handle, unsigned long mask,
- gfp_t flag, int node);
+ dma_addr_t *dma_handle, unsigned long mask,
+ gfp_t flag, int node);
extern void iommu_free_coherent(struct iommu_table *tbl, size_t size,
- void *vaddr, dma_addr_t dma_handle);
+ void *vaddr, dma_addr_t dma_handle);
extern dma_addr_t iommu_map_single(struct iommu_table *tbl, void *vaddr,
- size_t size, unsigned long mask,
- enum dma_data_direction direction);
+ size_t size, unsigned long mask,
+ enum dma_data_direction direction);
extern void iommu_unmap_single(struct iommu_table *tbl, dma_addr_t dma_handle,
- size_t size, enum dma_data_direction direction);
+ size_t size, enum dma_data_direction direction);
extern void iommu_init_early_pSeries(void);
extern void iommu_init_early_iSeries(void);
Index: linux-cell/arch/powerpc/kernel/vio.c
===================================================================
--- linux-cell.orig/arch/powerpc/kernel/vio.c 2006-11-02 13:22:04.000000000 +1100
+++ linux-cell/arch/powerpc/kernel/vio.c 2006-11-02 13:27:24.000000000 +1100
@@ -81,15 +81,15 @@ static struct iommu_table *vio_build_iom
struct iommu_table *tbl;
unsigned long offset, size;
- dma_window = get_property(dev->dev.platform_data,
- "ibm,my-dma-window", NULL);
+ dma_window = get_property(dev->dext.of_node,
+ "ibm,my-dma-window", NULL);
if (!dma_window)
return NULL;
tbl = kmalloc(sizeof(*tbl), GFP_KERNEL);
- of_parse_dma_window(dev->dev.platform_data, dma_window,
- &tbl->it_index, &offset, &size);
+ of_parse_dma_window(dev->dext.of_node, dma_window,
+ &tbl->it_index, &offset, &size);
/* TCE table size - measured in tce entries */
tbl->it_size = size >> IOMMU_PAGE_SHIFT;
@@ -115,9 +115,11 @@ static struct iommu_table *vio_build_iom
static const struct vio_device_id *vio_match_device(
const struct vio_device_id *ids, const struct vio_dev *dev)
{
+ struct device_ext *dext = device_get_ext(&dev->dev);
+
while (ids->type[0] != '\0') {
if ((strncmp(dev->type, ids->type, strlen(ids->type)) == 0) &&
- device_is_compatible(dev->dev.platform_data, ids->compat))
+ device_is_compatible(dext->of_node, ids->compat))
return ids;
ids++;
}
@@ -198,9 +200,11 @@ EXPORT_SYMBOL(vio_unregister_driver);
/* vio_dev refcount hit 0 */
static void __devinit vio_dev_release(struct device *dev)
{
- if (dev->platform_data) {
+ struct device_ext *dext = device_get_ext(dev);
+
+ if (dext && dext->of_node) {
/* XXX free TCE table */
- of_node_put(dev->platform_data);
+ of_node_put(dext->of_node);
}
kfree(to_vio_dev(dev));
}
@@ -210,7 +214,7 @@ static void __devinit vio_dev_release(st
* @of_node: The OF node for this device.
*
* Creates and initializes a vio_dev structure from the data in
- * of_node (dev.platform_data) and adds it to the list of virtual devices.
+ * of_node and adds it to the list of virtual devices.
* Returns a pointer to the created vio_dev or NULL if node has
* NULL device_type or compatible fields.
*/
@@ -240,8 +244,6 @@ struct vio_dev * __devinit vio_register_
if (viodev == NULL)
return NULL;
- viodev->dev.platform_data = of_node_get(of_node);
-
viodev->irq = irq_of_parse_and_map(of_node, 0);
snprintf(viodev->dev.bus_id, BUS_ID_SIZE, "%x", *unit_address);
@@ -254,7 +256,10 @@ struct vio_dev * __devinit vio_register_
if (unit_address != NULL)
viodev->unit_address = *unit_address;
}
- viodev->iommu_table = vio_build_iommu_table(viodev);
+ device_set_ext(&viodev->dev, &viodev->dext);
+ viodev->dext.of_node = of_node_get(of_node);
+ viodev->dext.dma_ops = &dma_iommu_ops;
+ viodev->dext.dma_data = vio_build_iommu_table(viodev);
/* init generic 'struct device' fields: */
viodev->dev.parent = &vio_bus_device.dev;
@@ -282,13 +287,16 @@ static int __init vio_bus_init(void)
int err;
struct device_node *node_vroot;
+ device_set_ext(&vio_bus_device.dev, &vio_bus_device.dext);
+
#ifdef CONFIG_PPC_ISERIES
if (firmware_has_feature(FW_FEATURE_ISERIES)) {
iommu_vio_init();
- vio_bus_device.iommu_table = &vio_iommu_table;
+ vio_bus_device.dext.dma_ops = &dma_iommu_ops;
+ vio_bus_device.dext.dma_data = &vio_iommu_table;
iSeries_vio_dev = &vio_bus_device.dev;
}
-#endif
+#endif /* CONFIG_PPC_ISERIES */
err = bus_register(&vio_bus_type);
if (err) {
@@ -336,7 +344,8 @@ static ssize_t name_show(struct device *
static ssize_t devspec_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
- struct device_node *of_node = dev->platform_data;
+ struct device_ext *dext = device_get_ext(dev);
+ struct device_node *of_node = dext->of_node;
return sprintf(buf, "%s\n", of_node ? of_node->full_name : "none");
}
@@ -353,62 +362,6 @@ void __devinit vio_unregister_device(str
}
EXPORT_SYMBOL(vio_unregister_device);
-static dma_addr_t vio_map_single(struct device *dev, void *vaddr,
- size_t size, enum dma_data_direction direction)
-{
- return iommu_map_single(to_vio_dev(dev)->iommu_table, vaddr, size,
- ~0ul, direction);
-}
-
-static void vio_unmap_single(struct device *dev, dma_addr_t dma_handle,
- size_t size, enum dma_data_direction direction)
-{
- iommu_unmap_single(to_vio_dev(dev)->iommu_table, dma_handle, size,
- direction);
-}
-
-static int vio_map_sg(struct device *dev, struct scatterlist *sglist,
- int nelems, enum dma_data_direction direction)
-{
- return iommu_map_sg(dev, to_vio_dev(dev)->iommu_table, sglist,
- nelems, ~0ul, direction);
-}
-
-static void vio_unmap_sg(struct device *dev, struct scatterlist *sglist,
- int nelems, enum dma_data_direction direction)
-{
- iommu_unmap_sg(to_vio_dev(dev)->iommu_table, sglist, nelems, direction);
-}
-
-static void *vio_alloc_coherent(struct device *dev, size_t size,
- dma_addr_t *dma_handle, gfp_t flag)
-{
- return iommu_alloc_coherent(to_vio_dev(dev)->iommu_table, size,
- dma_handle, ~0ul, flag, -1);
-}
-
-static void vio_free_coherent(struct device *dev, size_t size,
- void *vaddr, dma_addr_t dma_handle)
-{
- iommu_free_coherent(to_vio_dev(dev)->iommu_table, size, vaddr,
- dma_handle);
-}
-
-static int vio_dma_supported(struct device *dev, u64 mask)
-{
- return 1;
-}
-
-struct dma_mapping_ops vio_dma_ops = {
- .alloc_coherent = vio_alloc_coherent,
- .free_coherent = vio_free_coherent,
- .map_single = vio_map_single,
- .unmap_single = vio_unmap_single,
- .map_sg = vio_map_sg,
- .unmap_sg = vio_unmap_sg,
- .dma_supported = vio_dma_supported,
-};
-
static int vio_bus_match(struct device *dev, struct device_driver *drv)
{
const struct vio_dev *vio_dev = to_vio_dev(dev);
@@ -422,13 +375,17 @@ static int vio_hotplug(struct device *de
char *buffer, int buffer_size)
{
const struct vio_dev *vio_dev = to_vio_dev(dev);
- struct device_node *dn = dev->platform_data;
+ struct device_ext *dext = device_get_ext(dev);
+ struct device_node *dn;
const char *cp;
int length;
if (!num_envp)
return -ENOMEM;
+ if (!dext)
+ return -ENODEV;
+ dn = dext->of_node;
if (!dn)
return -ENODEV;
cp = get_property(dn, "compatible", &length);
@@ -465,7 +422,9 @@ struct bus_type vio_bus_type = {
*/
const void *vio_get_attribute(struct vio_dev *vdev, char *which, int *length)
{
- return get_property(vdev->dev.platform_data, which, length);
+ struct device_ext *dext = device_get_ext(&vdev->dev);
+
+ return get_property(dext->of_node, which, length);
}
EXPORT_SYMBOL(vio_get_attribute);
Index: linux-cell/include/asm-powerpc/vio.h
===================================================================
--- linux-cell.orig/include/asm-powerpc/vio.h 2006-11-02 13:22:04.000000000 +1100
+++ linux-cell/include/asm-powerpc/vio.h 2006-11-02 13:27:24.000000000 +1100
@@ -23,6 +23,7 @@
#include <asm/hvcall.h>
#include <asm/scatterlist.h>
+#include <asm/device_ext.h>
/*
* Architecture-specific constants for drivers to
@@ -45,12 +46,12 @@ struct iommu_table;
* The vio_dev structure is used to describe virtual I/O devices.
*/
struct vio_dev {
- struct iommu_table *iommu_table; /* vio_map_* uses this */
const char *name;
const char *type;
uint32_t unit_address;
unsigned int irq;
struct device dev;
+ struct device_ext dext;
};
struct vio_driver {
Index: linux-cell/arch/powerpc/kernel/pci_64.c
===================================================================
--- linux-cell.orig/arch/powerpc/kernel/pci_64.c 2006-11-02 13:27:12.000000000 +1100
+++ linux-cell/arch/powerpc/kernel/pci_64.c 2006-11-03 15:52:50.000000000 +1100
@@ -31,6 +31,7 @@
#include <asm/machdep.h>
#include <asm/ppc-pci.h>
#include <asm/firmware.h>
+#include <asm/device_ext.h>
#ifdef DEBUG
#include <asm/udbg.h>
@@ -63,7 +64,7 @@ void iSeries_pcibios_init(void);
LIST_HEAD(hose_list);
-struct dma_mapping_ops pci_dma_ops;
+struct dma_mapping_ops *pci_dma_ops;
EXPORT_SYMBOL(pci_dma_ops);
int global_phb_number; /* Global phb counter */
@@ -1213,15 +1214,42 @@ void __devinit pcibios_fixup_device_reso
}
EXPORT_SYMBOL(pcibios_fixup_device_resources);
+void __devinit pcibios_setup_new_device(struct pci_dev *dev)
+{
+ struct device_ext *dext;
+
+ if (device_get_ext(&dev->dev) != NULL)
+ return;
+
+ dext = kzalloc(sizeof(struct device_ext), GFP_KERNEL);
+ if (dext == NULL) {
+ printk(KERN_ERR "Failed to allocate device extension"
+ " for PCI device %s\n", pci_name(dev));
+ return;
+ }
+ device_set_ext(&dev->dev, dext);
+ dext->of_node = pci_device_to_OF_node(dev);
+ DBG("PCI device %s OF node: %s\n", pci_name(dev),
+ dext->of_node ? dext->of_node->full_name : "<none>");
+ dext->dma_ops = pci_dma_ops;
+
+#ifdef CONFIG_NUMA
+ dext->numa_node = pcibus_to_node(dev->bus);
+#endif
+ if (ppc_md.pci_dma_dev_setup)
+ ppc_md.pci_dma_dev_setup(dev);
+}
+EXPORT_SYMBOL(pcibios_setup_new_device);
static void __devinit do_bus_setup(struct pci_bus *bus)
{
struct pci_dev *dev;
- ppc_md.iommu_bus_setup(bus);
+ if (ppc_md.pci_dma_bus_setup)
+ ppc_md.pci_dma_bus_setup(bus);
list_for_each_entry(dev, &bus->devices, bus_list)
- ppc_md.iommu_dev_setup(dev);
+ pcibios_setup_new_device(dev);
/* Read default IRQs and fixup if necessary */
list_for_each_entry(dev, &bus->devices, bus_list) {
@@ -1429,3 +1457,25 @@ int pcibus_to_node(struct pci_bus *bus)
}
EXPORT_SYMBOL(pcibus_to_node);
#endif
+
+int pci_platform_notify(struct device * dev)
+{
+ return 0;
+}
+
+int pci_platform_notify_remove(struct device * dev)
+{
+ struct device_ext *dext = device_get_ext(dev);
+
+ DBG("%s:%s platform notify remove !\n",
+ dev_driver_string(dev), dev->bus_id);
+
+ if (dev->bus != &pci_bus_type)
+ return 0;
+
+ device_set_ext(dev, NULL);
+ mb();
+ kfree(dext);
+
+ return 0;
+}
Index: linux-cell/arch/powerpc/kernel/setup_64.c
===================================================================
--- linux-cell.orig/arch/powerpc/kernel/setup_64.c 2006-11-02 13:22:04.000000000 +1100
+++ linux-cell/arch/powerpc/kernel/setup_64.c 2006-11-03 15:52:50.000000000 +1100
@@ -33,6 +33,7 @@
#include <linux/serial.h>
#include <linux/serial_8250.h>
#include <linux/bootmem.h>
+#include <linux/pci.h>
#include <asm/io.h>
#include <asm/kdump.h>
#include <asm/prom.h>
@@ -530,6 +531,10 @@ void __init setup_arch(char **cmdline_p)
conswitchp = &dummy_con;
#endif
+#ifdef CONFIG_PCI
+ platform_notify = pci_platform_notify;
+ platform_notify_remove = pci_platform_notify_remove;
+#endif
ppc_md.setup_arch();
paging_init();
Index: linux-cell/arch/powerpc/platforms/pseries/iommu.c
===================================================================
--- linux-cell.orig/arch/powerpc/platforms/pseries/iommu.c 2006-11-02 13:22:04.000000000 +1100
+++ linux-cell/arch/powerpc/platforms/pseries/iommu.c 2006-11-03 15:39:50.000000000 +1100
@@ -44,6 +44,7 @@
#include <asm/tce.h>
#include <asm/ppc-pci.h>
#include <asm/udbg.h>
+#include <asm/device_ext.h>
#include "plpar_wrappers.h"
@@ -309,7 +310,7 @@ static void iommu_table_setparms_lpar(st
tbl->it_size = size >> IOMMU_PAGE_SHIFT;
}
-static void iommu_bus_setup_pSeries(struct pci_bus *bus)
+static void pci_dma_bus_setup_pSeries(struct pci_bus *bus)
{
struct device_node *dn;
struct iommu_table *tbl;
@@ -318,10 +319,9 @@ static void iommu_bus_setup_pSeries(stru
struct pci_dn *pci;
int children;
- DBG("iommu_bus_setup_pSeries, bus %p, bus->self %p\n", bus, bus->self);
-
dn = pci_bus_to_OF_node(bus);
- pci = PCI_DN(dn);
+
+ DBG("pci_dma_bus_setup_pSeries: setting up bus %s\n", dn->full_name);
if (bus->self) {
/* This is not a root bus, any setup will be done for the
@@ -329,6 +329,7 @@ static void iommu_bus_setup_pSeries(stru
*/
return;
}
+ pci = PCI_DN(dn);
/* Check if the ISA bus on the system is under
* this PHB.
@@ -390,17 +391,17 @@ static void iommu_bus_setup_pSeries(stru
}
-static void iommu_bus_setup_pSeriesLP(struct pci_bus *bus)
+static void pci_dma_bus_setup_pSeriesLP(struct pci_bus *bus)
{
struct iommu_table *tbl;
struct device_node *dn, *pdn;
struct pci_dn *ppci;
const void *dma_window = NULL;
- DBG("iommu_bus_setup_pSeriesLP, bus %p, bus->self %p\n", bus, bus->self);
-
dn = pci_bus_to_OF_node(bus);
+ DBG("pci_dma_bus_setup_pSeriesLP: setting up bus %s\n", dn->full_name);
+
/* Find nearest ibm,dma-window, walking up the device tree */
for (pdn = dn; pdn != NULL; pdn = pdn->parent) {
dma_window = get_property(pdn, "ibm,dma-window", NULL);
@@ -409,11 +410,15 @@ static void iommu_bus_setup_pSeriesLP(st
}
if (dma_window == NULL) {
- DBG("iommu_bus_setup_pSeriesLP: bus %s seems to have no ibm,dma-window property\n", dn->full_name);
+ DBG(" no ibm,dma-window property !\n");
return;
}
ppci = PCI_DN(pdn);
+
+ DBG(" parent is %s, iommu_table: 0x%p\n",
+ pdn->full_name, ppci->iommu_table);
+
if (!ppci->iommu_table) {
/* Bussubno hasn't been copied yet.
* Do it now because iommu_table_setparms_lpar needs it.
@@ -427,6 +432,7 @@ static void iommu_bus_setup_pSeriesLP(st
iommu_table_setparms_lpar(ppci->phb, pdn, tbl, dma_window);
ppci->iommu_table = iommu_init_table(tbl, ppci->phb->node);
+ DBG(" created table: %p\n", ppci->iommu_table);
}
if (pdn != dn)
@@ -434,27 +440,34 @@ static void iommu_bus_setup_pSeriesLP(st
}
-static void iommu_dev_setup_pSeries(struct pci_dev *dev)
+static void pci_dma_dev_setup_pSeries(struct pci_dev *dev)
{
- struct device_node *dn, *mydn;
+ struct device_ext *dext = device_get_ext(&dev->dev);
+ struct device_node *dn;
struct iommu_table *tbl;
- DBG("iommu_dev_setup_pSeries, dev %p (%s)\n", dev, pci_name(dev));
+ DBG("pci_dma_dev_setup_pSeries: %s\n", pci_name(dev));
- mydn = dn = pci_device_to_OF_node(dev);
+ if (dext == NULL) {
+ printk(KERN_ERR "iommu: Attempt to setup PCI dev %s "
+ "with no device extension !", pci_name(dev));
+ return;
+ }
+b
+ dn = dext->of_node;
/* If we're the direct child of a root bus, then we need to allocate
* an iommu table ourselves. The bus setup code should have setup
* the window sizes already.
*/
if (!dev->bus->self) {
+ struct pci_controller *phb = PCI_DN(dn)->phb;
+
DBG(" --> first child, no bridge. Allocating iommu table.\n");
tbl = kmalloc_node(sizeof(struct iommu_table), GFP_KERNEL,
- PCI_DN(dn)->phb->node);
- iommu_table_setparms(PCI_DN(dn)->phb, dn, tbl);
- PCI_DN(dn)->iommu_table = iommu_init_table(tbl,
- PCI_DN(dn)->phb->node);
-
+ phb->node);
+ iommu_table_setparms(phb, dn, tbl);
+ dext->dma_data = iommu_init_table(tbl, phb->node);
return;
}
@@ -465,11 +478,11 @@ static void iommu_dev_setup_pSeries(stru
while (dn && PCI_DN(dn) && PCI_DN(dn)->iommu_table == NULL)
dn = dn->parent;
- if (dn && PCI_DN(dn)) {
- PCI_DN(mydn)->iommu_table = PCI_DN(dn)->iommu_table;
- } else {
- DBG("iommu_dev_setup_pSeries, dev %p (%s) has no iommu table\n", dev, pci_name(dev));
- }
+ if (dn && PCI_DN(dn))
+ dext->dma_data = PCI_DN(dn)->iommu_table;
+ else
+ printk(KERN_WARNING "iommu: Device %s has no iommu table\n",
+ pci_name(dev));
}
static int iommu_reconfig_notifier(struct notifier_block *nb, unsigned long action, void *node)
@@ -495,13 +508,22 @@ static struct notifier_block iommu_recon
.notifier_call = iommu_reconfig_notifier,
};
-static void iommu_dev_setup_pSeriesLP(struct pci_dev *dev)
+static void pci_dma_dev_setup_pSeriesLP(struct pci_dev *dev)
{
+ struct device_ext *dext = device_get_ext(&dev->dev);
struct device_node *pdn, *dn;
struct iommu_table *tbl;
const void *dma_window = NULL;
struct pci_dn *pci;
+ DBG("pci_dma_dev_setup_pSeriesLP: %s\n", pci_name(dev));
+
+ if (dext == NULL) {
+ printk(KERN_ERR "iommu: Attempt to setup PCI dev %s "
+ "with no device extension !", pci_name(dev));
+ return;
+ }
+
/* dev setup for LPAR is a little tricky, since the device tree might
* contain the dma-window properties per-device and not neccesarily
* for the bus. So we need to search upwards in the tree until we
@@ -509,9 +531,7 @@ static void iommu_dev_setup_pSeriesLP(st
* already allocated.
*/
dn = pci_device_to_OF_node(dev);
-
- DBG("iommu_dev_setup_pSeriesLP, dev %p (%s) %s\n",
- dev, pci_name(dev), dn->full_name);
+ DBG(" node is %s\n", dn->full_name);
for (pdn = dn; pdn && PCI_DN(pdn) && !PCI_DN(pdn)->iommu_table;
pdn = pdn->parent) {
@@ -520,16 +540,17 @@ static void iommu_dev_setup_pSeriesLP(st
break;
}
+ DBG(" parent is %s\n", pdn->full_name);
+
/* Check for parent == NULL so we don't try to setup the empty EADS
* slots on POWER4 machines.
*/
if (dma_window == NULL || pdn->parent == NULL) {
- DBG("No dma window for device, linking to parent\n");
- PCI_DN(dn)->iommu_table = PCI_DN(pdn)->iommu_table;
+ DBG(" no dma window for device, linking to parent\n");
+ dext->dma_data = PCI_DN(pdn)->iommu_table;
return;
- } else {
- DBG("Found DMA window, allocating table\n");
}
+ DBG(" found DMA window, table: %p\n", pci->iommu_table);
pci = PCI_DN(pdn);
if (!pci->iommu_table) {
@@ -542,24 +563,20 @@ static void iommu_dev_setup_pSeriesLP(st
iommu_table_setparms_lpar(pci->phb, pdn, tbl, dma_window);
pci->iommu_table = iommu_init_table(tbl, pci->phb->node);
+ DBG(" created table: %p\n", pci->iommu_table);
}
- if (pdn != dn)
- PCI_DN(dn)->iommu_table = pci->iommu_table;
+ dext->dma_data = pci->iommu_table;
}
-static void iommu_bus_setup_null(struct pci_bus *b) { }
-static void iommu_dev_setup_null(struct pci_dev *d) { }
-
/* These are called very early. */
void iommu_init_early_pSeries(void)
{
if (of_chosen && get_property(of_chosen, "linux,iommu-off", NULL)) {
/* Direct I/O, IOMMU off */
- ppc_md.iommu_dev_setup = iommu_dev_setup_null;
- ppc_md.iommu_bus_setup = iommu_bus_setup_null;
- pci_direct_iommu_init();
-
+ ppc_md.pci_dma_dev_setup = NULL;
+ ppc_md.pci_dma_bus_setup = NULL;
+ pci_dma_ops = &dma_direct_ops;
return;
}
@@ -572,19 +589,19 @@ void iommu_init_early_pSeries(void)
ppc_md.tce_free = tce_free_pSeriesLP;
}
ppc_md.tce_get = tce_get_pSeriesLP;
- ppc_md.iommu_bus_setup = iommu_bus_setup_pSeriesLP;
- ppc_md.iommu_dev_setup = iommu_dev_setup_pSeriesLP;
+ ppc_md.pci_dma_bus_setup = pci_dma_bus_setup_pSeriesLP;
+ ppc_md.pci_dma_dev_setup = pci_dma_dev_setup_pSeriesLP;
} else {
ppc_md.tce_build = tce_build_pSeries;
ppc_md.tce_free = tce_free_pSeries;
ppc_md.tce_get = tce_get_pseries;
- ppc_md.iommu_bus_setup = iommu_bus_setup_pSeries;
- ppc_md.iommu_dev_setup = iommu_dev_setup_pSeries;
+ ppc_md.pci_dma_bus_setup = pci_dma_bus_setup_pSeries;
+ ppc_md.pci_dma_dev_setup = pci_dma_dev_setup_pSeries;
}
pSeries_reconfig_notifier_register(&iommu_reconfig_nb);
- pci_iommu_init();
+ pci_dma_ops = &dma_iommu_ops;
}
Index: linux-cell/arch/powerpc/platforms/pseries/pci_dlpar.c
===================================================================
--- linux-cell.orig/arch/powerpc/platforms/pseries/pci_dlpar.c 2006-11-02 13:22:04.000000000 +1100
+++ linux-cell/arch/powerpc/platforms/pseries/pci_dlpar.c 2006-11-03 15:33:34.000000000 +1100
@@ -93,8 +93,8 @@ pcibios_fixup_new_pci_devices(struct pci
if (list_empty(&dev->global_list)) {
int i;
- /* Need to setup IOMMU tables */
- ppc_md.iommu_dev_setup(dev);
+ /* Create device extension and setup iommu table */
+ pcibios_setup_new_device(dev);
if(fix_bus)
pcibios_fixup_device_resources(dev, bus);
Index: linux-cell/arch/powerpc/sysdev/dart_iommu.c
===================================================================
--- linux-cell.orig/arch/powerpc/sysdev/dart_iommu.c 2006-11-02 13:22:04.000000000 +1100
+++ linux-cell/arch/powerpc/sysdev/dart_iommu.c 2006-11-02 13:27:24.000000000 +1100
@@ -45,6 +45,7 @@
#include <asm/cacheflush.h>
#include <asm/lmb.h>
#include <asm/ppc-pci.h>
+#include <asm/device_ext.h>
#include "dart.h"
@@ -289,24 +290,23 @@ static void iommu_table_dart_setup(void)
set_bit(iommu_table_dart.it_size - 1, iommu_table_dart.it_map);
}
-static void iommu_dev_setup_dart(struct pci_dev *dev)
+static void pci_dma_dev_setup_dart(struct pci_dev *dev)
{
- struct device_node *dn;
+ struct device_ext *dext = device_get_ext(&dev->dev);
+
+ if (dext == NULL) {
+ printk(KERN_ERR "dart: Attempt to setup PCI dev %s "
+ "with no device extension !", pci_name(dev));
+ return;
+ }
/* We only have one iommu table on the mac for now, which makes
* things simple. Setup all PCI devices to point to this table
- *
- * We must use pci_device_to_OF_node() to make sure that
- * we get the real "final" pointer to the device in the
- * pci_dev sysdata and not the temporary PHB one
*/
- dn = pci_device_to_OF_node(dev);
-
- if (dn)
- PCI_DN(dn)->iommu_table = &iommu_table_dart;
+ dext->dma_data = &iommu_table_dart;
}
-static void iommu_bus_setup_dart(struct pci_bus *bus)
+static void pci_dma_bus_setup_dart(struct pci_bus *bus)
{
struct device_node *dn;
@@ -321,9 +321,6 @@ static void iommu_bus_setup_dart(struct
PCI_DN(dn)->iommu_table = &iommu_table_dart;
}
-static void iommu_dev_setup_null(struct pci_dev *dev) { }
-static void iommu_bus_setup_null(struct pci_bus *bus) { }
-
void iommu_init_early_dart(void)
{
struct device_node *dn;
@@ -344,22 +341,21 @@ void iommu_init_early_dart(void)
/* Initialize the DART HW */
if (dart_init(dn) == 0) {
- ppc_md.iommu_dev_setup = iommu_dev_setup_dart;
- ppc_md.iommu_bus_setup = iommu_bus_setup_dart;
+ ppc_md.pci_dma_dev_setup = pci_dma_dev_setup_dart;
+ ppc_md.pci_dma_bus_setup = pci_dma_bus_setup_dart;
/* Setup pci_dma ops */
- pci_iommu_init();
-
+ pci_dma_ops = &dma_iommu_ops;
return;
}
bail:
/* If init failed, use direct iommu and null setup functions */
- ppc_md.iommu_dev_setup = iommu_dev_setup_null;
- ppc_md.iommu_bus_setup = iommu_bus_setup_null;
+ ppc_md.pci_dma_dev_setup = NULL;
+ ppc_md.pci_dma_bus_setup = NULL;
/* Setup pci_dma ops */
- pci_direct_iommu_init();
+ pci_dma_ops = &dma_direct_ops;
}
Index: linux-cell/include/asm-powerpc/machdep.h
===================================================================
--- linux-cell.orig/include/asm-powerpc/machdep.h 2006-11-02 13:27:13.000000000 +1100
+++ linux-cell/include/asm-powerpc/machdep.h 2006-11-03 15:33:34.000000000 +1100
@@ -84,8 +84,8 @@ struct machdep_calls {
unsigned long (*tce_get)(struct iommu_table *tbl,
long index);
void (*tce_flush)(struct iommu_table *tbl);
- void (*iommu_dev_setup)(struct pci_dev *dev);
- void (*iommu_bus_setup)(struct pci_bus *bus);
+ void (*pci_dma_dev_setup)(struct pci_dev *dev);
+ void (*pci_dma_bus_setup)(struct pci_bus *bus);
#endif /* CONFIG_PPC64 */
int (*probe)(void);
Index: linux-cell/include/asm-powerpc/pci-bridge.h
===================================================================
--- linux-cell.orig/include/asm-powerpc/pci-bridge.h 2006-11-02 13:22:04.000000000 +1100
+++ linux-cell/include/asm-powerpc/pci-bridge.h 2006-11-03 15:33:35.000000000 +1100
@@ -161,6 +161,9 @@ static inline unsigned long pci_address_
}
#endif
+extern int pci_platform_notify(struct device * dev);
+extern int pci_platform_notify_remove(struct device * dev);
+
/* Return values for ppc_md.pci_probe_mode function */
#define PCI_PROBE_NONE -1 /* Don't look at this bus at all */
#define PCI_PROBE_NORMAL 0 /* Do normal PCI probing */
Index: linux-cell/include/asm-powerpc/pci.h
===================================================================
--- linux-cell.orig/include/asm-powerpc/pci.h 2006-11-02 13:22:04.000000000 +1100
+++ linux-cell/include/asm-powerpc/pci.h 2006-11-02 13:27:24.000000000 +1100
@@ -76,15 +76,15 @@ static inline int pcibios_prep_mwi(struc
return 0;
}
-extern struct dma_mapping_ops pci_dma_ops;
+extern struct dma_mapping_ops *pci_dma_ops;
/* For DAC DMA, we currently don't support it by default, but
* we let 64-bit platforms override this.
*/
static inline int pci_dac_dma_supported(struct pci_dev *hwdev,u64 mask)
{
- if (pci_dma_ops.dac_dma_supported)
- return pci_dma_ops.dac_dma_supported(&hwdev->dev, mask);
+ if (pci_dma_ops && pci_dma_ops->dac_dma_supported)
+ return pci_dma_ops->dac_dma_supported(&hwdev->dev, mask);
return 0;
}
@@ -216,6 +216,8 @@ extern int remap_bus_range(struct pci_bu
extern void pcibios_fixup_device_resources(struct pci_dev *dev,
struct pci_bus *bus);
+extern void pcibios_setup_new_device(struct pci_dev *dev);
+
extern void pcibios_claim_one_bus(struct pci_bus *b);
extern struct pci_controller *init_phb_dynamic(struct device_node *dn);
Index: linux-cell/arch/powerpc/kernel/Makefile
===================================================================
--- linux-cell.orig/arch/powerpc/kernel/Makefile 2006-11-02 13:27:23.000000000 +1100
+++ linux-cell/arch/powerpc/kernel/Makefile 2006-11-02 13:27:24.000000000 +1100
@@ -63,8 +63,7 @@ obj-$(CONFIG_PPC_UDBG_16550) += legacy_s
module-$(CONFIG_PPC64) += module_64.o
obj-$(CONFIG_MODULES) += $(module-y)
-pci64-$(CONFIG_PPC64) += pci_64.o pci_dn.o pci_iommu.o \
- pci_direct_iommu.o iomap.o
+pci64-$(CONFIG_PPC64) += pci_64.o pci_dn.o iomap.o
pci32-$(CONFIG_PPC32) := pci_32.o
obj-$(CONFIG_PCI) += $(pci64-y) $(pci32-y)
kexec-$(CONFIG_PPC64) := machine_kexec_64.o
Index: linux-cell/arch/powerpc/kernel/ibmebus.c
===================================================================
--- linux-cell.orig/arch/powerpc/kernel/ibmebus.c 2006-11-02 13:22:04.000000000 +1100
+++ linux-cell/arch/powerpc/kernel/ibmebus.c 2006-11-02 13:27:24.000000000 +1100
@@ -112,7 +112,7 @@ static int ibmebus_dma_supported(struct
return 1;
}
-struct dma_mapping_ops ibmebus_dma_ops = {
+static struct dma_mapping_ops ibmebus_dma_ops = {
.alloc_coherent = ibmebus_alloc_coherent,
.free_coherent = ibmebus_free_coherent,
.map_single = ibmebus_map_single,
@@ -176,6 +176,10 @@ static struct ibmebus_dev* __devinit ibm
dev->ofdev.dev.bus = &ibmebus_bus_type;
dev->ofdev.dev.release = ibmebus_dev_release;
+ device_set_ext(&dev->ofdev.dev, &dev->dext);
+ dev->dext.of_node = dev->ofdev.node;
+ dev->dext.dma_ops = &ibmebus_dma_ops;
+
/* An ibmebusdev is based on a of_device. We have to change the
* bus type to use our own DMA mapping operations.
*/
Index: linux-cell/arch/powerpc/platforms/cell/iommu.c
===================================================================
--- linux-cell.orig/arch/powerpc/platforms/cell/iommu.c 2006-11-02 13:22:04.000000000 +1100
+++ linux-cell/arch/powerpc/platforms/cell/iommu.c 2006-11-03 15:33:33.000000000 +1100
@@ -255,9 +255,6 @@ static void enable_mapping(void __iomem
set_iost_origin(mmio_base);
}
-static void iommu_dev_setup_null(struct pci_dev *d) { }
-static void iommu_bus_setup_null(struct pci_bus *b) { }
-
struct cell_iommu {
unsigned long base;
unsigned long mmio_base;
@@ -306,12 +303,15 @@ static void cell_do_map_iommu(struct cel
}
}
-static void iommu_devnode_setup(struct device_node *d)
+static void pci_dma_cell_bus_setup(struct pci_bus *b)
{
const unsigned int *ioid;
unsigned long map_start, map_size, token;
const unsigned long *dma_window;
struct cell_iommu *iommu;
+ struct device_node *d;
+
+ d = pci_bus_to_OF_node(b);
ioid = get_property(d, "ioid", NULL);
if (!ioid)
@@ -330,12 +330,6 @@ static void iommu_devnode_setup(struct d
cell_do_map_iommu(iommu, *ioid, map_start, map_size);
}
-static void iommu_bus_setup(struct pci_bus *b)
-{
- struct device_node *d = (struct device_node *)b->sysdata;
- iommu_devnode_setup(d);
-}
-
static int cell_map_iommu_hardcoded(int num_nodes)
{
@@ -499,16 +493,13 @@ void cell_init_iommu(void)
if (setup_bus) {
pr_debug("%s: IOMMU mapping activated\n", __FUNCTION__);
- ppc_md.iommu_dev_setup = iommu_dev_setup_null;
- ppc_md.iommu_bus_setup = iommu_bus_setup;
+ ppc_md.pci_dma_bus_setup = pci_dma_cell_bus_setup;
} else {
pr_debug("%s: IOMMU mapping activated, "
"no device action necessary\n", __FUNCTION__);
/* Direct I/O, IOMMU off */
- ppc_md.iommu_dev_setup = iommu_dev_setup_null;
- ppc_md.iommu_bus_setup = iommu_bus_setup_null;
}
}
- pci_dma_ops = cell_iommu_ops;
+ pci_dma_ops = &cell_iommu_ops;
}
Index: linux-cell/include/asm-powerpc/ibmebus.h
===================================================================
--- linux-cell.orig/include/asm-powerpc/ibmebus.h 2006-11-02 13:22:04.000000000 +1100
+++ linux-cell/include/asm-powerpc/ibmebus.h 2006-11-02 13:27:24.000000000 +1100
@@ -43,12 +43,13 @@
#include <linux/interrupt.h>
#include <linux/mod_devicetable.h>
#include <asm/of_device.h>
+#include <asm/device_ext.h>
-extern struct dma_mapping_ops ibmebus_dma_ops;
extern struct bus_type ibmebus_bus_type;
struct ibmebus_dev {
const char *name;
+ struct device_ext dext;
struct of_device ofdev;
};
Index: linux-cell/include/asm-powerpc/of_device.h
===================================================================
--- linux-cell.orig/include/asm-powerpc/of_device.h 2006-11-02 13:27:23.000000000 +1100
+++ linux-cell/include/asm-powerpc/of_device.h 2006-11-02 13:27:24.000000000 +1100
@@ -5,6 +5,7 @@
#include <linux/device.h>
#include <linux/mod_devicetable.h>
#include <asm/prom.h>
+#include <asm/device_ext.h>
/*
@@ -14,8 +15,9 @@
*/
struct of_device
{
- struct device_node *node; /* OF device node */
+ struct device_node *node; /* to be obsoleted */
u64 dma_mask; /* DMA mask */
+ struct device_ext dext;
struct device dev; /* Generic device interface */
};
#define to_of_device(d) container_of(d, struct of_device, dev)
Index: linux-cell/arch/powerpc/kernel/of_platform.c
===================================================================
--- linux-cell.orig/arch/powerpc/kernel/of_platform.c 2006-11-02 13:27:23.000000000 +1100
+++ linux-cell/arch/powerpc/kernel/of_platform.c 2006-11-03 15:33:34.000000000 +1100
@@ -22,7 +22,7 @@
#include <asm/dcr.h>
#include <asm/of_device.h>
#include <asm/of_platform.h>
-
+#include <asm/topology.h>
/*
* The list of OF IDs below is used for matching bus types in the
@@ -220,6 +220,14 @@ struct of_device* of_platform_device_cre
dev->dev.parent = parent;
dev->dev.bus = &of_platform_bus_type;
dev->dev.release = of_release_dev;
+ device_set_ext(&dev->dev, &dev->dext);
+ dev->dext.of_node = np;
+ dev->dext.numa_node = of_node_to_nid(np);
+
+ /* We do not fill the DMA ops for platform devices by default.
+ * This is currently the responsibility of the platform code
+ * to do such, possibly using a device notifier
+ */
if (bus_id)
strlcpy(dev->dev.bus_id, bus_id, BUS_ID_SIZE);
Index: linux-cell/arch/powerpc/platforms/iseries/iommu.c
===================================================================
--- linux-cell.orig/arch/powerpc/platforms/iseries/iommu.c 2006-11-02 13:16:16.000000000 +1100
+++ linux-cell/arch/powerpc/platforms/iseries/iommu.c 2006-11-03 15:43:10.000000000 +1100
@@ -27,6 +27,7 @@
#include <linux/types.h>
#include <linux/dma-mapping.h>
#include <linux/list.h>
+#include <linux/pci.h>
#include <asm/iommu.h>
#include <asm/tce.h>
@@ -36,6 +37,7 @@
#include <asm/pci-bridge.h>
#include <asm/iseries/hv_call_xm.h>
#include <asm/iseries/iommu.h>
+#include <asm/device_ext.h>
static void tce_build_iSeries(struct iommu_table *tbl, long index, long npages,
unsigned long uaddr, enum dma_data_direction direction)
@@ -168,14 +170,21 @@ static struct iommu_table *iommu_table_f
}
-void iommu_devnode_init_iSeries(struct device_node *dn)
+void iommu_devnode_init_iSeries(struct pci_dev *pdev, struct device_node *dn)
{
struct iommu_table *tbl;
+ struct device_ext *dext = device_get_ext(&pdev->dev);
struct pci_dn *pdn = PCI_DN(dn);
const u32 *lsn = get_property(dn, "linux,logical-slot-number", NULL);
BUG_ON(lsn == NULL);
+ if (dext == NULL) {
+ printk(KERN_ERR "iommu: Attempt to setup PCI dev %s "
+ "with no device extension !", pci_name(pdev));
+ return;
+ }
+
tbl = kmalloc(sizeof(struct iommu_table), GFP_KERNEL);
iommu_table_getparms_iSeries(pdn->busno, *lsn, 0, tbl);
@@ -186,19 +195,14 @@ void iommu_devnode_init_iSeries(struct d
pdn->iommu_table = iommu_init_table(tbl, -1);
else
kfree(tbl);
+ dext->dma_data = pdn->iommu_table;
}
#endif
-static void iommu_dev_setup_iSeries(struct pci_dev *dev) { }
-static void iommu_bus_setup_iSeries(struct pci_bus *bus) { }
-
void iommu_init_early_iSeries(void)
{
ppc_md.tce_build = tce_build_iSeries;
ppc_md.tce_free = tce_free_iSeries;
- ppc_md.iommu_dev_setup = iommu_dev_setup_iSeries;
- ppc_md.iommu_bus_setup = iommu_bus_setup_iSeries;
-
- pci_iommu_init();
+ pci_dma_ops = &dma_iommu_ops;
}
Index: linux-cell/arch/powerpc/platforms/iseries/pci.c
===================================================================
--- linux-cell.orig/arch/powerpc/platforms/iseries/pci.c 2006-11-03 15:33:33.000000000 +1100
+++ linux-cell/arch/powerpc/platforms/iseries/pci.c 2006-11-03 15:37:23.000000000 +1100
@@ -253,7 +253,7 @@ void __init iSeries_pci_final_fixup(void
PCI_DN(node)->pcidev = pdev;
allocate_device_bars(pdev);
iSeries_Device_Information(pdev, DeviceCount);
- iommu_devnode_init_iSeries(node);
+ iommu_devnode_init_iSeries(pdev, node);
} else
printk("PCI: Device Tree not found for 0x%016lX\n",
(unsigned long)pdev);
Index: linux-cell/include/asm-powerpc/iseries/iommu.h
===================================================================
--- linux-cell.orig/include/asm-powerpc/iseries/iommu.h 2006-10-06 13:45:32.000000000 +1000
+++ linux-cell/include/asm-powerpc/iseries/iommu.h 2006-11-03 15:41:45.000000000 +1100
@@ -21,11 +21,13 @@
* Boston, MA 02111-1307 USA
*/
+struct pci_dev;
struct device_node;
struct iommu_table;
/* Creates table for an individual device node */
-extern void iommu_devnode_init_iSeries(struct device_node *dn);
+extern void iommu_devnode_init_iSeries(struct pci_dev *pdev,
+ struct device_node *dn);
/* Get table parameters from HV */
extern void iommu_table_getparms_iSeries(unsigned long busno,
^ permalink raw reply
* [PATCH/RFC] powerpc: make pci use device notifier
From: Benjamin Herrenschmidt @ 2006-11-03 21:22 UTC (permalink / raw)
To: linuxppc-dev list
This is just an add-on to my previous patch to make it use the new
device notifier thingy that I added to gregkh tree instead of the old
style function pointer hooks
Index: linux-cell/arch/powerpc/kernel/setup_64.c
===================================================================
--- linux-cell.orig/arch/powerpc/kernel/setup_64.c 2006-10-26 16:43:32.000000000 +1000
+++ linux-cell/arch/powerpc/kernel/setup_64.c 2006-10-26 16:44:09.000000000 +1000
@@ -531,10 +531,6 @@ void __init setup_arch(char **cmdline_p)
conswitchp = &dummy_con;
#endif
-#ifdef CONFIG_PCI
- platform_notify = pci_platform_notify;
- platform_notify_remove = pci_platform_notify_remove;
-#endif
ppc_md.setup_arch();
paging_init();
Index: linux-cell/arch/powerpc/kernel/pci_64.c
===================================================================
--- linux-cell.orig/arch/powerpc/kernel/pci_64.c 2006-10-26 16:43:32.000000000 +1000
+++ linux-cell/arch/powerpc/kernel/pci_64.c 2006-10-26 16:44:09.000000000 +1000
@@ -22,6 +22,7 @@
#include <linux/list.h>
#include <linux/syscalls.h>
#include <linux/irq.h>
+#include <linux/notifier.h>
#include <asm/processor.h>
#include <asm/io.h>
@@ -554,6 +555,29 @@ void __devinit scan_phb(struct pci_contr
hose->last_busno = bus->subordinate = pci_scan_child_bus(bus);
}
+static int ppc_pci_dev_notify(struct notifier_block *nb, unsigned long action,
+ void *data)
+{
+ struct device *dev = data;
+ struct device_ext *dext;
+
+ if (action == BUS_NOTIFY_DEL_DEVICE) {
+ dext = device_get_ext(dev);
+
+ DBG("%s:%s platform notify remove !\n",
+ dev_driver_string(dev), dev->bus_id);
+
+ device_set_ext(dev, NULL);
+ kfree(dext);
+ }
+
+ return 0;
+}
+
+static struct notifier_block ppc_pci_dev_notifier = {
+ .notifier_call = ppc_pci_dev_notify
+};
+
static int __init pcibios_init(void)
{
struct pci_controller *hose, *tmp;
@@ -566,6 +590,8 @@ static int __init pcibios_init(void)
if (firmware_has_feature(FW_FEATURE_ISERIES))
iSeries_pcibios_init();
+ register_bus_notifier(&pci_bus_type, &ppc_pci_dev_notifier);
+
printk(KERN_DEBUG "PCI: Probing PCI hardware\n");
/* Scan all of the recorded PCI controllers. */
@@ -1458,24 +1484,3 @@ int pcibus_to_node(struct pci_bus *bus)
EXPORT_SYMBOL(pcibus_to_node);
#endif
-int pci_platform_notify(struct device * dev)
-{
- return 0;
-}
-
-int pci_platform_notify_remove(struct device * dev)
-{
- struct device_ext *dext = device_get_ext(dev);
-
- DBG("%s:%s platform notify remove !\n",
- dev_driver_string(dev), dev->bus_id);
-
- if (dev->bus != &pci_bus_type)
- return 0;
-
- device_set_ext(dev, NULL);
- mb();
- kfree(dext);
-
- return 0;
-}
^ permalink raw reply
* Re: [PATCH/RFC 1/3] powerpc: of_platform improvements
From: Benjamin Herrenschmidt @ 2006-11-03 21:25 UTC (permalink / raw)
To: linuxppc-dev list
In-Reply-To: <1162588703.10630.107.camel@localhost.localdomain>
Ignore the 1/3 ... I'll post a complete serie with all my patches next
week, right now, I'm sending cherry picked ones that are big enough to
need early commenting.
Ben.
^ permalink raw reply
* [PATCH/RFC] powerpc: PCI busses can have a parent
From: Benjamin Herrenschmidt @ 2006-11-03 21:26 UTC (permalink / raw)
To: linuxppc-dev list
This patch adds a parent field to the pci_controller structure so that
a PCI bus can be rooted under a specified parent in sysfs
Add a "parent" struct device to our PCI host bridge data structure so that
PCI can be rooted of another device. (Note that arch/ppc doesn't use it,
only arch/powerpc)
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Index: linux-cell/arch/powerpc/kernel/pci_32.c
===================================================================
--- linux-cell.orig/arch/powerpc/kernel/pci_32.c 2006-10-23 14:41:37.000000000 +1000
+++ linux-cell/arch/powerpc/kernel/pci_32.c 2006-10-25 14:33:07.000000000 +1000
@@ -1268,7 +1268,10 @@ pcibios_init(void)
if (pci_assign_all_buses)
hose->first_busno = next_busno;
hose->last_busno = 0xff;
- bus = pci_scan_bus(hose->first_busno, hose->ops, hose);
+ bus = pci_scan_bus_parented(hose->parent, hose->first_busno,
+ hose->ops, hose);
+ if (bus)
+ pci_bus_add_devices(bus);
hose->last_busno = bus->subordinate;
if (pci_assign_all_buses || next_busno <= hose->last_busno)
next_busno = hose->last_busno + pcibios_assign_bus_offset;
Index: linux-cell/arch/powerpc/kernel/pci_64.c
===================================================================
--- linux-cell.orig/arch/powerpc/kernel/pci_64.c 2006-10-25 14:32:08.000000000 +1000
+++ linux-cell/arch/powerpc/kernel/pci_64.c 2006-10-25 14:33:07.000000000 +1000
@@ -519,7 +519,7 @@ void __devinit scan_phb(struct pci_contr
DBG("Scanning PHB %s\n", node ? node->full_name : "<NO NAME>");
- bus = pci_create_bus(NULL, hose->first_busno, hose->ops, node);
+ bus = pci_create_bus(hose->parent, hose->first_busno, hose->ops, node);
if (bus == NULL) {
printk(KERN_ERR "Failed to create bus for PCI domain %04x\n",
hose->global_number);
Index: linux-cell/include/asm-powerpc/pci-bridge.h
===================================================================
--- linux-cell.orig/include/asm-powerpc/pci-bridge.h 2006-10-25 14:23:57.000000000 +1000
+++ linux-cell/include/asm-powerpc/pci-bridge.h 2006-10-25 14:33:07.000000000 +1000
@@ -25,6 +25,7 @@ struct pci_controller {
int node;
void *arch_data;
struct list_head list_node;
+ struct device *parent;
int first_busno;
int last_busno;
Index: linux-cell/include/asm-ppc/pci-bridge.h
===================================================================
--- linux-cell.orig/include/asm-ppc/pci-bridge.h 2006-01-14 14:43:33.000000000 +1100
+++ linux-cell/include/asm-ppc/pci-bridge.h 2006-10-25 14:33:07.000000000 +1000
@@ -43,6 +43,7 @@ struct pci_controller {
struct pci_controller *next;
struct pci_bus *bus;
void *arch_data;
+ struct device *parent;
int first_busno;
int last_busno;
^ permalink raw reply
* [PATCH/RFC] powerpc: Create PCI busses from of_platform
From: Benjamin Herrenschmidt @ 2006-11-03 21:28 UTC (permalink / raw)
To: linuxppc-dev list
This patch adds an of_platform_driver that matches against PCI host
bridges. RTAS's setup_phb() is renamed to rtas_setup_phb() and a
ppc_md. hook is added for platforms to initialize the newly discovered
PHBs (cell is set to use rtas since cell will use that new mecanism)
Index: linux-cell/arch/powerpc/kernel/of_platform.c
===================================================================
--- linux-cell.orig/arch/powerpc/kernel/of_platform.c 2006-10-26 17:35:36.000000000 +1000
+++ linux-cell/arch/powerpc/kernel/of_platform.c 2006-10-26 17:35:41.000000000 +1000
@@ -1,6 +1,7 @@
/*
* Copyright (C) 2006 Benjamin Herrenschmidt, IBM Corp.
* <benh@kernel.crashing.org>
+ * and Arnd Bergmann, IBM Corp.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -17,12 +18,15 @@
#include <linux/module.h>
#include <linux/mod_devicetable.h>
#include <linux/slab.h>
+#include <linux/pci.h>
#include <asm/errno.h>
#include <asm/dcr.h>
#include <asm/of_device.h>
#include <asm/of_platform.h>
#include <asm/topology.h>
+#include <asm/pci-bridge.h>
+#include <asm/ppc-pci.h>
/*
* The list of OF IDs below is used for matching bus types in the
@@ -378,3 +382,96 @@ struct of_device *of_find_device_by_phan
return NULL;
}
EXPORT_SYMBOL(of_find_device_by_phandle);
+
+
+#ifdef CONFIG_PCI
+
+static int __devinit of_pci_phb_probe(struct of_device *dev,
+ const struct of_device_id *match)
+{
+ struct pci_controller *phb;
+
+ /* Check if we can do that ... */
+ if (ppc_md.pci_setup_phb == NULL)
+ return -ENODEV;
+
+ printk(KERN_INFO "Setting up PCI bus %s\n", dev->node->full_name);
+
+ /* Alloc and setup PHB data structure */
+ phb = pcibios_alloc_controller(dev->node);
+ if (!phb)
+ return -ENODEV;
+
+ /* Setup parent in sysfs */
+ phb->parent = &dev->dev;
+
+ /* Setup the PHB using arch provided callback */
+ if (ppc_md.pci_setup_phb(phb)) {
+ pcibios_free_controller(phb);
+ return -ENODEV;
+ }
+
+ /* Process "ranges" property */
+ pci_process_bridge_OF_ranges(phb, dev->node, 0);
+
+ /* Setup IO space.
+ * This will not work properly for ISA IOs, something needs to be done
+ * about it if we ever generalize that way of probing PCI brigdes
+ */
+ pci_setup_phb_io_dynamic(phb, 0);
+
+ /* Init pci_dn data structures */
+ pci_devs_phb_init_dynamic(phb);
+
+ /* Register devices with EEH */
+#ifdef CONFIG_EEH
+ if (dev->node->child)
+ eeh_add_device_tree_early(dev->node);
+#endif /* CONFIG_EEH */
+
+ /* Scan the bus */
+ scan_phb(phb);
+
+ /* Claim resources. This might need some rework as well depending
+ * wether we are doing probe-only or not, like assigning unassigned
+ * resources etc...
+ */
+ pcibios_claim_one_bus(phb->bus);
+
+ /* Finish EEH setup */
+#ifdef CONFIG_EEH
+ eeh_add_device_tree_late(phb->bus);
+#endif
+
+ /* Add probed PCI devices to the device model */
+ pci_bus_add_devices(phb->bus);
+
+ return 0;
+}
+
+static struct of_device_id of_pci_phb_ids[] = {
+ { .type = "pci", },
+ { .type = "pcix", },
+ { .type = "pcie", },
+ { .type = "pciex", },
+ { .type = "ht", },
+ {}
+};
+
+static struct of_platform_driver of_pci_phb_driver = {
+ .name = "of-pci",
+ .match_table = of_pci_phb_ids,
+ .probe = of_pci_phb_probe,
+ .driver = {
+ .multithread_probe = 1,
+ },
+};
+
+static __init int of_pci_phb_init(void)
+{
+ return of_register_platform_driver(&of_pci_phb_driver);
+}
+
+device_initcall(of_pci_phb_init);
+
+#endif /* CONFIG_PCI */
Index: linux-cell/arch/powerpc/kernel/pci_64.c
===================================================================
--- linux-cell.orig/arch/powerpc/kernel/pci_64.c 2006-10-26 17:35:39.000000000 +1000
+++ linux-cell/arch/powerpc/kernel/pci_64.c 2006-10-26 17:35:41.000000000 +1000
@@ -214,6 +214,10 @@ struct pci_controller * pcibios_alloc_co
void pcibios_free_controller(struct pci_controller *phb)
{
+ spin_lock(&hose_spinlock);
+ list_del(&phb->list_node);
+ spin_unlock(&hose_spinlock);
+
if (phb->is_dynamic)
kfree(phb);
}
@@ -1284,6 +1288,11 @@ static void __devinit do_bus_setup(struc
void __devinit pcibios_fixup_bus(struct pci_bus *bus)
{
struct pci_dev *dev = bus->self;
+ struct device_node *np;
+
+ np = pci_bus_to_OF_node(bus);
+
+ DBG("pcibios_fixup_bus(%s)\n", np ? np->full_name : "<???>");
if (dev && pci_probe_only &&
(dev->class >> 8) == PCI_CLASS_BRIDGE_PCI) {
Index: linux-cell/include/asm-powerpc/machdep.h
===================================================================
--- linux-cell.orig/include/asm-powerpc/machdep.h 2006-10-26 17:35:36.000000000 +1000
+++ linux-cell/include/asm-powerpc/machdep.h 2006-10-26 17:35:41.000000000 +1000
@@ -26,6 +26,7 @@ struct device_node;
struct iommu_table;
struct rtc_time;
struct file;
+struct pci_controller;
#ifdef CONFIG_KEXEC
struct kimage;
#endif
@@ -107,6 +108,9 @@ struct machdep_calls {
int (*pci_probe_mode)(struct pci_bus *);
void (*pci_irq_fixup)(struct pci_dev *dev);
+ /* To setup PHBs when using automatic OF platform driver for PCI */
+ int (*pci_setup_phb)(struct pci_controller *host);
+
void (*restart)(char *cmd);
void (*power_off)(void);
void (*halt)(void);
Index: linux-cell/arch/powerpc/kernel/rtas_pci.c
===================================================================
--- linux-cell.orig/arch/powerpc/kernel/rtas_pci.c 2006-10-26 17:35:38.000000000 +1000
+++ linux-cell/arch/powerpc/kernel/rtas_pci.c 2006-10-26 17:35:41.000000000 +1000
@@ -257,8 +257,10 @@ static int phb_set_bus_ranges(struct dev
return 0;
}
-int __devinit setup_phb(struct device_node *dev, struct pci_controller *phb)
+int __devinit rtas_setup_phb(struct pci_controller *phb)
{
+ struct device_node *dev = phb->arch_data;
+
if (is_python(dev))
python_countermeasures(dev);
@@ -290,7 +292,7 @@ unsigned long __init find_and_init_phbs(
phb = pcibios_alloc_controller(node);
if (!phb)
continue;
- setup_phb(node, phb);
+ rtas_setup_phb(phb);
pci_process_bridge_OF_ranges(phb, node, 0);
pci_setup_phb_io(phb, index == 0);
index++;
@@ -362,7 +364,6 @@ int pcibios_remove_root_bus(struct pci_c
}
}
- list_del(&phb->list_node);
pcibios_free_controller(phb);
return 0;
Index: linux-cell/arch/powerpc/platforms/pseries/pci_dlpar.c
===================================================================
--- linux-cell.orig/arch/powerpc/platforms/pseries/pci_dlpar.c 2006-10-26 17:35:36.000000000 +1000
+++ linux-cell/arch/powerpc/platforms/pseries/pci_dlpar.c 2006-10-26 17:35:41.000000000 +1000
@@ -195,7 +195,7 @@ struct pci_controller * __devinit init_p
phb = pcibios_alloc_controller(dn);
if (!phb)
return NULL;
- setup_phb(dn, phb);
+ rtas_setup_phb(phb);
pci_process_bridge_OF_ranges(phb, dn, 0);
pci_setup_phb_io_dynamic(phb, primary);
Index: linux-cell/include/asm-powerpc/ppc-pci.h
===================================================================
--- linux-cell.orig/include/asm-powerpc/ppc-pci.h 2006-10-26 17:35:36.000000000 +1000
+++ linux-cell/include/asm-powerpc/ppc-pci.h 2006-10-26 17:35:41.000000000 +1000
@@ -36,14 +36,14 @@ typedef void *(*traverse_func)(struct de
void *traverse_pci_devices(struct device_node *start, traverse_func pre,
void *data);
-void pci_devs_phb_init(void);
-void pci_devs_phb_init_dynamic(struct pci_controller *phb);
-int setup_phb(struct device_node *dev, struct pci_controller *phb);
-void __devinit scan_phb(struct pci_controller *hose);
+extern void pci_devs_phb_init(void);
+extern void pci_devs_phb_init_dynamic(struct pci_controller *phb);
+extern void scan_phb(struct pci_controller *hose);
/* From rtas_pci.h */
-void init_pci_config_tokens (void);
-unsigned long get_phb_buid (struct device_node *);
+extern void init_pci_config_tokens (void);
+extern unsigned long get_phb_buid (struct device_node *);
+extern int rtas_setup_phb(struct pci_controller *phb);
/* From pSeries_pci.h */
extern void pSeries_final_fixup(void);
Index: linux-cell/arch/powerpc/platforms/cell/setup.c
===================================================================
--- linux-cell.orig/arch/powerpc/platforms/cell/setup.c 2006-10-26 17:35:36.000000000 +1000
+++ linux-cell/arch/powerpc/platforms/cell/setup.c 2006-10-26 17:35:41.000000000 +1000
@@ -264,6 +264,7 @@ define_machine(cell) {
.check_legacy_ioport = cell_check_legacy_ioport,
.progress = cell_progress,
.init_IRQ = cell_init_irq,
+ .pci_setup_phb = rtas_setup_phb,
#ifdef CONFIG_KEXEC
.machine_kexec = default_machine_kexec,
.machine_kexec_prepare = default_machine_kexec_prepare,
^ permalink raw reply
* Re: [patch 08/16] powerpc: remove EMBEDDED6xx Kconfig entry
From: Benjamin Herrenschmidt @ 2006-11-03 21:32 UTC (permalink / raw)
To: Olof Johansson; +Cc: linuxppc-dev, paulus
In-Reply-To: <20061103145300.411931b7@localhost.localdomain>
On Fri, 2006-11-03 at 14:53 -0600, Olof Johansson wrote:
> On Sat, 04 Nov 2006 07:46:15 +1100 Benjamin Herrenschmidt <benh@kernel.crashing.org> wrote:
>
> > Yes. Though I hope we'll see some alternatives to uboot soon
> >
> > /me looks towards ojn and segher....
>
> There's already PIBS, isn't there?
But that's not a public/opensource thing people use regulary is it ?
Ben.
^ permalink raw reply
* Re: [PATCH/RFC] Hookable IO operations
From: Arnd Bergmann @ 2006-11-03 22:20 UTC (permalink / raw)
To: linuxppc-dev
In-Reply-To: <1162588367.10630.100.camel@localhost.localdomain>
On Friday 03 November 2006 22:12, Benjamin Herrenschmidt wrote:
> +/*
> + *
> + * Low level MMIO accessors
> + *
> + * This provides the non-bus specific accessors to MMIO. Those are PowerPC
> + * specific and thus shouldn't be used in generic code. The accessors
> + * provided here are:
> + *
> + * in_8, in_le16, in_be16, in_le32, in_be32, in_le64, in_be64
> + * out_8, out_le16, out_be16, out_le32, out_be32, out_le64, out_be64
> + * _insb, _insw_ns, _insl_ns, _outsb, _outsw_ns, _outsl_ns
> + *
> + * Those operate direction on a kernel virtual address. Note that the prototype
> + * for the out_* accessors has the arguments in opposite order from the usual
> + * linux PCI accessors. Unlike those, they take the address first and the value
> + * next.
> + *
> + * Note: I might drop the _ns suffix on the stream operations soon as it is
> + * simply normal for stream operations to not swap in the first place.
> + *
> + */
> +
> +#define DEF_MMIO_IN(name, type, insn) \
> +static inline type in_##name(const volatile type __iomem *addr) \
> +{ \
> + type ret; \
> + __asm__ __volatile__("sync;" insn ";twi 0,%0,0;isync" \
> + : "=r" (ret) : "r" (addr), "m" (*addr)); \
> + return ret; \
> +}
> +
> +#define DEF_MMIO_OUT(name, type, insn) \
> +static inline void out_##name(volatile type __iomem *addr, type val) \
> +{ \
> + __asm__ __volatile__("sync;" insn \
> + : "=m" (*addr) : "r" (val), "r" (addr)); \
> + get_paca()->io_sync = 1; \
> +}
> +
> +
> +#define DEF_MMIO_IN_BE(pfx, size, insn) \
> + DEF_MMIO_IN(pfx##size, u##size, __stringify(insn)"%U2%X2 %0,%2")
> +#define DEF_MMIO_IN_LE(pfx, size, insn) \
> + DEF_MMIO_IN(pfx##size, u##size, __stringify(insn)" %0,0,%1")
> +
> +#define DEF_MMIO_OUT_BE(pfx, size, insn) \
> + DEF_MMIO_OUT(pfx##size, u##size, __stringify(insn)"%U0%X0 %1,%0")
> +#define DEF_MMIO_OUT_LE(pfx, size, insn) \
> + DEF_MMIO_OUT(pfx##size, u##size, __stringify(insn)" %1,0,%2")
> +
> +DEF_MMIO_IN_BE( , 8, lbz);
> +DEF_MMIO_IN_BE(be, 16, lhz);
> +DEF_MMIO_IN_BE(be, 32, lwz);
> +DEF_MMIO_IN_BE(be, 64, ld);
> +DEF_MMIO_IN_LE(le, 16, lhbrx);
> +DEF_MMIO_IN_LE(le, 32, lwbrx);
> +
> +DEF_MMIO_OUT_BE( , 8, stb);
> +DEF_MMIO_OUT_BE(be, 16, sth);
> +DEF_MMIO_OUT_BE(be, 32, stw);
> +DEF_MMIO_OUT_BE(be, 64, std);
> +DEF_MMIO_OUT_LE(le, 16, sthbrx);
> +DEF_MMIO_OUT_LE(le, 32, stwbrx);
I think it would be helpful to not generate the function name itself,
but pass it down to the macro, so you grep for the definition, either
DEF_MMIO_IN_BE(in_be16, u16, lwz)
or going further, making it look more like a declaration
static inline u16 DEF_MMIO_IN_BE(in_be16, u16, lwz)
which may even do the right thing with ctags (need to check that)
> +/*
> + * IO stream instructions are defined out of line
> + */
> +extern void _insb(volatile u8 __iomem *port, void *buf, long count);
> +extern void _outsb(volatile u8 __iomem *port, const void *buf, long count);
> +extern void _insw_ns(volatile u16 __iomem *port, void *buf, long count);
> +extern void _outsw_ns(volatile u16 __iomem *port, const void *buf, long count);
> +extern void _insl_ns(volatile u32 __iomem *port, void *buf, long count);
> +extern void _outsl_ns(volatile u32 __iomem *port, const void *buf, long count);
If you leave out the 'extern', it fits into a normal line ;-)
> +
> +/*
> + * PCI IO accessors.
> + *
> + * Right now, we still use the eeh versions inline but that might change
> + * as EEH can use the new hook mecanism, provided it doesn't impact
> + * performances too much
> + */
> +
> +#include <asm/eeh.h>
> +
> +#define DEF_PCI_DT_b u8
> +#define DEF_PCI_DT_w u16
> +#define DEF_PCI_DT_l u32
> +#define DEF_PCI_DT_q u64
> +
> +#define __do_writeb(val, addr) out_8(addr, val)
> +#define __do_writew(val, addr) out_le16(addr, val)
> +#define __do_writel(val, addr) out_le32(addr, val)
> +#define __do_writeq(val, addr) out_le64(addr, val)
> +
> +#ifdef CONFIG_PPC_INDIRECT_IO
> +#define DEF_PCI_HOOK(x) x
> +#else
> +#define DEF_PCI_HOOK(x) NULL
> +#endif
> +
> +#define DEF_PCI_AC_IN_MMIO(ts) \
> +extern DEF_PCI_DT_##ts (*__ind_read##ts)(const volatile void __iomem * addr); \
> +static inline DEF_PCI_DT_##ts read##ts(const volatile void __iomem * addr) \
> +{ \
> + if (DEF_PCI_HOOK(__ind_read##ts) != NULL) \
> + return __ind_read##ts(addr); \
> + return eeh_read##ts(addr); \
> +}
> +
> +#define DEF_PCI_AC_IN_PIO(ts) \
> +extern DEF_PCI_DT_##ts (*__ind_in##ts)(unsigned long port); \
> +static inline DEF_PCI_DT_##ts in##ts(unsigned long port) \
> +{ \
> + if (DEF_PCI_HOOK(__ind_in##ts) != NULL) \
> + return __ind_in##ts(port); \
> + return read##ts((void __iomem *)pci_io_base + port); \
> +}
> +
> +#define DEF_PCI_AC_OUT_MMIO(ts) \
> +extern void (*__ind_write##ts)(DEF_PCI_DT_##ts val, \
> + volatile void __iomem *addr); \
> +static inline void write##ts(DEF_PCI_DT_##ts val, volatile void __iomem *addr) \
> +{ \
> + if (DEF_PCI_HOOK(__ind_write##ts) != NULL) \
> + __ind_write##ts(val, addr); \
> + else \
> + __do_write##ts(val, addr); \
> +}
> +
> +#define DEF_PCI_AC_OUT_PIO(ts) \
> +extern void (*__ind_out##ts)(DEF_PCI_DT_##ts val, unsigned long port); \
> +static inline void out##ts(DEF_PCI_DT_##ts val, unsigned long port) \
> +{ \
> + if (DEF_PCI_HOOK(__ind_out##ts) != NULL) \
> + __ind_out##ts(val, port); \
> + else \
> + write##ts(val, (void __iomem *)pci_io_base + port); \
> +}
> +
> +#define DEF_PCI_AC_MMIO(ts, dir) DEF_PCI_AC_##dir##_MMIO(ts)
> +#define DEF_PCI_AC_PIO(ts, dir) DEF_PCI_AC_##dir##_PIO(ts)
> +
> +#define DEF_PCI_AC(ts, dir) DEF_PCI_AC_MMIO(ts, dir) \
> + DEF_PCI_AC_PIO(ts, dir)
> +DEF_PCI_AC(b, IN)
> +DEF_PCI_AC(w, IN)
> +DEF_PCI_AC(l, IN)
> +DEF_PCI_AC_MMIO(q, IN)
> +DEF_PCI_AC(b, OUT)
> +DEF_PCI_AC(w, OUT)
> +DEF_PCI_AC(l, OUT)
> +DEF_PCI_AC_MMIO(q, OUT)
similarly here, you could write these using slightly different macros
as
DEF_PCI_AC_OUT_MMIO(writeb, u8)
DEF_PCI_AC_OUT_PIO(outb, u8)
DEF_PCI_AC_OUT_MMIO(writew, u16)
DEF_PCI_AC_OUT_PIO(outw, u16)
> +
> +/* We still use EEH versions for now. Ultimately, we might just get rid of
> + * EEH in here and use it as a set of __memset_io etc... hooks
> + */
Yes, I fully agree. The definition of eeh_memset_io and the others
looks like they really want to be out-of-line.
> +
> +extern void (*__memset_io)(volatile void __iomem *addr, int c,
> + unsigned long n);
> +extern void (*__memcpy_fromio)(void *dest, const volatile void __iomem *src,
> + unsigned long n);
> +extern void (*__memcpy_toio)(volatile void __iomem *dest, const void *src,
> + unsigned long n);
Why are these all separate symbols? Wouldn't it be clearer to group them
in ppc_md, or a similar structure of function pointers?
> --- linux-cell.orig/arch/powerpc/kernel/setup_64.c 2006-11-03 15:52:54.000000000 +1100
> +++ linux-cell/arch/powerpc/kernel/setup_64.c 2006-11-03 18:51:14.000000000 +1100
> @@ -599,3 +599,48 @@ void __init setup_per_cpu_areas(void)
> }
> }
> #endif
> +
> +
> +#ifdef CONFIG_PPC_INDIRECT_IO
> +
> +#define EXP_PCI_AC_IN_MMIO(ts) \
> +DEF_PCI_DT_##ts (*__ind_read##ts)(const volatile void __iomem * addr); \
> +EXPORT_SYMBOL(__ind_read##ts);
> +
> +#define EXP_PCI_AC_IN_PIO(ts) \
> +DEF_PCI_DT_##ts (*__ind_in##ts)(unsigned long port); \
> +EXPORT_SYMBOL(__ind_in##ts);
> +
> +#define EXP_PCI_AC_OUT_MMIO(ts) \
> +void (*__ind_write##ts)(DEF_PCI_DT_##ts val, \
> + volatile void __iomem *addr); \
> +EXPORT_SYMBOL(__ind_write##ts);
> +
> +#define EXP_PCI_AC_OUT_PIO(ts) \
> +void (*__ind_out##ts)(DEF_PCI_DT_##ts val, unsigned long port); \
> +EXPORT_SYMBOL(__ind_out##ts);
> +
> +#define EXP_PCI_AC_MMIO(ts, dir) EXP_PCI_AC_##dir##_MMIO(ts)
> +#define EXP_PCI_AC_PIO(ts, dir) EXP_PCI_AC_##dir##_PIO(ts)
> +
> +#define EXP_PCI_AC(ts, dir) EXP_PCI_AC_MMIO(ts, dir) \
> + EXP_PCI_AC_PIO(ts, dir)
> +EXP_PCI_AC(b, IN)
> +EXP_PCI_AC(w, IN)
> +EXP_PCI_AC(l, IN)
> +EXP_PCI_AC_MMIO(q, IN)
> +EXP_PCI_AC(b, OUT)
> +EXP_PCI_AC(w, OUT)
> +EXP_PCI_AC(l, OUT)
> +EXP_PCI_AC_MMIO(q, OUT)
This is the point where it gets completely unreadable. I ended up
running the macros through 'gcc -E' to see what they do ;-)
If you resolve all the macros, you actually get fewer lines, and
it suddenly becomes readable, as well as parsable with grep and ctags:
u8 (*__ind_readb) (const volatile void __iomem * addr);
EXPORT_SYMBOL(__ind_readb);
u8 (*__ind_inb) (unsigned long port);
EXPORT_SYMBOL(__ind_inb);
u16 (*__ind_readw) (const volatile void __iomem * addr);
EXPORT_SYMBOL(__ind_readw);
u16 (*__ind_inw) (unsigned long port);
...
I do the same when I start using macros, it's always hard to know exactly
when to stop ;-)
> -static u8 iSeries_Read_Byte(const volatile void __iomem *IoAddress)
> +static u8 iseries_readb(const volatile void __iomem *IoAddress)
Since you're converting iSeries_Read_Byte from SilLycAps, shouldn't
you change IoAddress to something more sensible at the same time?
> {
> u64 BarOffset;
> u64 dsa;
> @@ -462,7 +411,8 @@ static u8 iSeries_Read_Byte(const volati
> num_printed = 0;
> }
> if (num_printed++ < 10)
> - printk(KERN_ERR "iSeries_Read_Byte: invalid access at IO address %p\n", IoAddress);
> + printk(KERN_ERR "iSeries_Read_Byte: invalid access at IO address %p\n",
> + IoAddress);
> return 0xff;
And the name in the comment should also be changed.
Arnd <><
^ permalink raw reply
* Re: [PATCH/RFC] Hookable IO operations
From: Benjamin Herrenschmidt @ 2006-11-03 22:32 UTC (permalink / raw)
To: Arnd Bergmann; +Cc: linuxppc-dev
In-Reply-To: <200611032320.34762.arnd@arndb.de>
> I think it would be helpful to not generate the function name itself,
> but pass it down to the macro, so you grep for the definition, either
>
> DEF_MMIO_IN_BE(in_be16, u16, lwz)
>
> or going further, making it look more like a declaration
>
> static inline u16 DEF_MMIO_IN_BE(in_be16, u16, lwz)
>
> which may even do the right thing with ctags (need to check that)
I'll look into it.
> > +/*
> > + * IO stream instructions are defined out of line
> > + */
> > +extern void _insb(volatile u8 __iomem *port, void *buf, long count);
> > +extern void _outsb(volatile u8 __iomem *port, const void *buf, long count);
> > +extern void _insw_ns(volatile u16 __iomem *port, void *buf, long count);
> > +extern void _outsw_ns(volatile u16 __iomem *port, const void *buf, long count);
> > +extern void _insl_ns(volatile u32 __iomem *port, void *buf, long count);
> > +extern void _outsl_ns(volatile u32 __iomem *port, const void *buf, long count);
>
> If you leave out the 'extern', it fits into a normal line ;-)
Did I change them from the initial definition ? Anyway, I dislike
prototypes in headers without "extern".
>
> similarly here, you could write these using slightly different macros
> as
>
> DEF_PCI_AC_OUT_MMIO(writeb, u8)
> DEF_PCI_AC_OUT_PIO(outb, u8)
> DEF_PCI_AC_OUT_MMIO(writew, u16)
> DEF_PCI_AC_OUT_PIO(outw, u16)
I'll look at it.
> > +
> > +/* We still use EEH versions for now. Ultimately, we might just get rid of
> > + * EEH in here and use it as a set of __memset_io etc... hooks
> > + */
>
> Yes, I fully agree. The definition of eeh_memset_io and the others
> looks like they really want to be out-of-line.
Yes.
> > +
> > +extern void (*__memset_io)(volatile void __iomem *addr, int c,
> > + unsigned long n);
> > +extern void (*__memcpy_fromio)(void *dest, const volatile void __iomem *src,
> > + unsigned long n);
> > +extern void (*__memcpy_toio)(volatile void __iomem *dest, const void *src,
> > + unsigned long n);
>
> Why are these all separate symbols? Wouldn't it be clearer to group them
> in ppc_md, or a similar structure of function pointers?
Because the IO ones are separate already and I want to keep things
consistent with them.
> This is the point where it gets completely unreadable. I ended up
> running the macros through 'gcc -E' to see what they do ;-)
Come on ... :-) They are almost the same as the ones in the .h, they
just only define the function pointer.
> If you resolve all the macros, you actually get fewer lines, and
> it suddenly becomes readable, as well as parsable with grep and ctags:
>
> u8 (*__ind_readb) (const volatile void __iomem * addr);
> EXPORT_SYMBOL(__ind_readb);
> u8 (*__ind_inb) (unsigned long port);
> EXPORT_SYMBOL(__ind_inb);
> u16 (*__ind_readw) (const volatile void __iomem * addr);
> EXPORT_SYMBOL(__ind_readw);
> u16 (*__ind_inw) (unsigned long port);
> ...
>
> I do the same when I start using macros, it's always hard to know exactly
> when to stop ;-)
I'll look and see what the result looks like.
> > -static u8 iSeries_Read_Byte(const volatile void __iomem *IoAddress)
> > +static u8 iseries_readb(const volatile void __iomem *IoAddress)
>
> Since you're converting iSeries_Read_Byte from SilLycAps, shouldn't
> you change IoAddress to something more sensible at the same time?
No, I'm only changing the prototype & name to better match my hooks,
further cleanups of the content of these functions is something I'll do
in a separate patch.
> > {
> > u64 BarOffset;
> > u64 dsa;
> > @@ -462,7 +411,8 @@ static u8 iSeries_Read_Byte(const volati
> > num_printed = 0;
> > }
> > if (num_printed++ < 10)
> > - printk(KERN_ERR "iSeries_Read_Byte: invalid access at IO address %p\n", IoAddress);
> > + printk(KERN_ERR "iSeries_Read_Byte: invalid access at IO address %p\n",
> > + IoAddress);
> > return 0xff;
>
> And the name in the comment should also be changed.
Ooopsa.
Ben.
^ permalink raw reply
* Re: [PATCH/RFC] Hookable IO operations
From: Arnd Bergmann @ 2006-11-03 22:48 UTC (permalink / raw)
To: Benjamin Herrenschmidt; +Cc: linuxppc-dev
In-Reply-To: <1162593121.10630.132.camel@localhost.localdomain>
On Friday 03 November 2006 23:32, Benjamin Herrenschmidt wrote:
> > If you leave out the 'extern', it fits into a normal line ;-)
>
> Did I change them from the initial definition ? Anyway, I dislike
> prototypes in headers without "extern".
I prefer writing down the extern as well, but the common style
seems to have moved away from it now.
>
> > > +
> > > +extern void (*__memset_io)(volatile void __iomem *addr, int c,
> > > + unsigned long n);
> > > +extern void (*__memcpy_fromio)(void *dest, const volatile void __iomem *src,
> > > + unsigned long n);
> > > +extern void (*__memcpy_toio)(volatile void __iomem *dest, const void *src,
> > > + unsigned long n);
> >
> > Why are these all separate symbols? Wouldn't it be clearer to group them
> > in ppc_md, or a similar structure of function pointers?
>
> Because the IO ones are separate already and I want to keep things
> consistent with them.
Actually I meant all of the I/O pointers, not just these three. When
you were describing your idea to me, I was thinking of something like
struct ppc_io {
void (*writeb)(u8 val);
void (*writew)(u16 val);
void (*writel)(u32 val);
void (*writeq)(u64 val);
...
void (*memset_io)(volatile void __iomem *addr, int c,
unsigned long n);
void (*__memcpy_fromio)(void *dest,
const volatile void __iomem *src, unsigned long n);
void (*__memcpy_toio)(volatile void __iomem *dest,
const void *src, unsigned long n);
} *ppc_io;
Did you never consider this, or did you make your mind up in the
process?
Is your current code more efficient?
> > > -static u8 iSeries_Read_Byte(const volatile void __iomem *IoAddress)
> > > +static u8 iseries_readb(const volatile void __iomem *IoAddress)
> >
> > Since you're converting iSeries_Read_Byte from SilLycAps, shouldn't
> > you change IoAddress to something more sensible at the same time?
>
> No, I'm only changing the prototype & name to better match my hooks,
> further cleanups of the content of these functions is something I'll do
> in a separate patch.
ok, makes sense.
Arnd <><
^ permalink raw reply
* Re: [PATCH/RFC] Hookable IO operations
From: Benjamin Herrenschmidt @ 2006-11-03 22:56 UTC (permalink / raw)
To: Arnd Bergmann; +Cc: linuxppc-dev
In-Reply-To: <200611032348.38402.arnd@arndb.de>
]
> Actually I meant all of the I/O pointers, not just these three. When
> you were describing your idea to me, I was thinking of something like
>
> struct ppc_io {
> void (*writeb)(u8 val);
> void (*writew)(u16 val);
> void (*writel)(u32 val);
> void (*writeq)(u64 val);
> ...
> void (*memset_io)(volatile void __iomem *addr, int c,
> unsigned long n);
> void (*__memcpy_fromio)(void *dest,
> const volatile void __iomem *src, unsigned long n);
> void (*__memcpy_toio)(volatile void __iomem *dest,
> const void *src, unsigned long n);
> } *ppc_io;
>
> Did you never consider this, or did you make your mind up in the
> process?
I considered this and decided against it while doing the macro since I
could get the hooks auto-generated easier as globals, but I can still
change it, it's not that much bloat and might indeed look nicer.
> Is your current code more efficient?
I don't think there is a difference is ppc_io is a global struct rather
than a pointer, like ppc_md.
Ben.
^ permalink raw reply
* Re: [patch 08/16] powerpc: remove EMBEDDED6xx Kconfig entry
From: Olof Johansson @ 2006-11-03 23:49 UTC (permalink / raw)
To: Benjamin Herrenschmidt; +Cc: linuxppc-dev, paulus
In-Reply-To: <1162589534.10630.127.camel@localhost.localdomain>
On Sat, 04 Nov 2006 08:32:14 +1100 Benjamin Herrenschmidt <benh@kernel.crashing.org> wrote:
> But that's not a public/opensource thing people use regulary is it ?
Might not be. I don't know what AMCC use for their eval boards, if it's
u-boot or PIBS or something else.
-Olof
^ permalink raw reply
* Re: [PATCH/RFC] Hookable IO operations
From: Arnd Bergmann @ 2006-11-04 0:15 UTC (permalink / raw)
To: linuxppc-dev
In-Reply-To: <1162594589.10630.135.camel@localhost.localdomain>
On Friday 03 November 2006 23:56, Benjamin Herrenschmidt wrote:
>
> > Did you never consider this, or did you make your mind up in the
> > process?
>
> I considered this and decided against it while doing the macro since I
> could get the hooks auto-generated easier as globals, but I can still
> change it, it's not that much bloat and might indeed look nicer.
I've just tried hacking something up, this is the best I could come up
with using the structure:
/* are these all we need, or did I miss any? */
struct ppc_io {
void (*writeb)(u8 val);
void (*writew)(u16 val);
void (*writel)(u32 val);
void (*writeq)(u64 val);
u8 (*readb)(void);
u16 (*readw)(void);
u32 (*readl)(void);
u64 (*readq)(void);
void (*outb)(u8 val);
void (*outw)(u16 val);
void (*outl)(u32 val);
void (*outq)(u64 val);
u8 (*inb)(void);
u16 (*inw)(void);
u32 (*inl)(void);
u64 (*inq)(void);
void (*memset_io)(volatile void __iomem *addr, int c, unsigned long n);
void (*memcpy_fromio)(void *dest,
const volatile void __iomem *src, unsigned long n);
void (*memcpy_toio)(volatile void __iomem *dest,
const void *src, unsigned long n);
} ppc_io;
/* all these should be static inline or extern */
void direct_writeb(u8 val);
void direct_writew(u16 val);
void direct_writel(u32 val);
void direct_writeq(u64 val);
u8 direct_readb(void);
u16 direct_readw(void);
u32 direct_readl(void);
u64 direct_readq(void);
void direct_outb(u8 val);
void direct_outw(u16 val);
void direct_outl(u32 val);
void direct_outq(u64 val);
u8 direct_inb(void);
u16 direct_inw(void);
u32 direct_inl(void);
u64 direct_inq(void);
void direct_memset_io(volatile void __iomem *addr, int c,
unsigned long n);
void direct_memcpy_fromio(void *dest,
const volatile void __iomem *src, unsigned long n);
void direct_memcpy_toio(volatile void __iomem *dest,
const void *src, unsigned long n);
/* a simple indirection more than your code, going
through the structure */
#ifdef CONFIG_INDIRECT_IO
#define ppc_io_indirect(x) ppc_io.x
#else
#define ppc_io_indirect(x) NULL
#endif
#define DEF_IO_OUT(name, arg) \
static inline void name(arg val) \
{ \
if (ppc_io_indirect(name)) \
return ppc_io.name(val); \
else \
return direct_ ## name(val); \
}
#define DEF_IO_IN(name, arg) \
static inline arg name(void) \
{ \
if (ppc_io_indirect(name)) \
return ppc_io.name(); \
else \
return direct_ ## name(); \
}
DEF_IO_OUT(writeb, u8)
DEF_IO_OUT(writew, u16)
DEF_IO_OUT(writel, u32)
DEF_IO_OUT(writeq, u64)
DEF_IO_IN(readb, u8)
DEF_IO_IN(readw, u16)
DEF_IO_IN(readl, u32)
DEF_IO_IN(readq, u64)
DEF_IO_OUT(outb, u8)
DEF_IO_OUT(outw, u16)
DEF_IO_OUT(outl, u32)
DEF_IO_OUT(outq, u64)
DEF_IO_IN(inb, u8)
DEF_IO_IN(inw, u16)
DEF_IO_IN(inl, u32)
DEF_IO_IN(inq, u64)
/* using variadic macros makes this somewhat simpler
* than writing the whole prototype */
#define memset_io(arg...) \
do { \
if (ppc_io_indirect(memset_io)) \
ppc_io.memset_io(arg); \
else \
direct_memset_io(arg); \
} while (0)
#define memcpy_fromio(arg...) \
do { \
if (ppc_io_indirect(memcpy_fromio)) \
ppc_io.memcpy_fromio(arg); \
else \
direct_memcpy_fromio(arg); \
} while (0)
#define memcpy_toio(arg...) \
do { \
if (ppc_io_indirect(memcpy_toio)) \
ppc_io.memcpy_toio(arg); \
else \
direct_memcpy_toio(arg); \
} while (0)
^ permalink raw reply
* Re: [PATCH/RFC] Hookable IO operations
From: Benjamin Herrenschmidt @ 2006-11-04 1:06 UTC (permalink / raw)
To: Arnd Bergmann; +Cc: linuxppc-dev
In-Reply-To: <200611040115.34235.arnd@arndb.de>
On Sat, 2006-11-04 at 01:15 +0100, Arnd Bergmann wrote:
> void (*outq)(u64 val);
> u64 (*inq)(void);
There is no outq/intq :-) Also, we need the ins{b,w,l}/outs{n,w,l} ones.
I haven' hooked them yet but we'll need them and we'll need the MMIO
versions of them which aren't defined properly except with iomap. That
is 12 more hooks...
> void (*memset_io)(volatile void __iomem *addr, int c, unsigned long n);
> void (*memcpy_fromio)(void *dest,
> const volatile void __iomem *src, unsigned long n);
> void (*memcpy_toio)(volatile void __iomem *dest,
> const void *src, unsigned long n);
> } ppc_io;
>
> /* all these should be static inline or extern */
> void direct_writeb(u8 val);
> void direct_writew(u16 val);
> void direct_writel(u32 val);
> void direct_writeq(u64 val);
> u8 direct_readb(void);
> u16 direct_readw(void);
> u32 direct_readl(void);
> u64 direct_readq(void);
> void direct_outb(u8 val);
> void direct_outw(u16 val);
> void direct_outl(u32 val);
> void direct_outq(u64 val);
> u8 direct_inb(void);
> u16 direct_inw(void);
> u32 direct_inl(void);
> u64 direct_inq(void);
Well, I still need to use the EEH version for now so I'd rather stick to
what my current macros are doing. You are also not passing any
address :)
> void direct_memset_io(volatile void __iomem *addr, int c,
> unsigned long n);
> void direct_memcpy_fromio(void *dest,
> const volatile void __iomem *src, unsigned long n);
> void direct_memcpy_toio(volatile void __iomem *dest,
> const void *src, unsigned long n);
>
> /* a simple indirection more than your code, going
> through the structure */
> #ifdef CONFIG_INDIRECT_IO
> #define ppc_io_indirect(x) ppc_io.x
> #else
> #define ppc_io_indirect(x) NULL
> #endif
>
> #define DEF_IO_OUT(name, arg) \
> static inline void name(arg val) \
> { \
> if (ppc_io_indirect(name)) \
> return ppc_io.name(val); \
> else \
> return direct_ ## name(val); \
> }
Address type is different between IO and MMIO too. IO takes unsigned
long port and MMIO takes void __iomem *, with a const for the read
versions...
> #define DEF_IO_IN(name, arg) \
> static inline arg name(void) \
> { \
> if (ppc_io_indirect(name)) \
> return ppc_io.name(); \
> else \
> return direct_ ## name(); \
> }
>
> DEF_IO_OUT(writeb, u8)
> DEF_IO_OUT(writew, u16)
> DEF_IO_OUT(writel, u32)
> DEF_IO_OUT(writeq, u64)
> DEF_IO_IN(readb, u8)
> DEF_IO_IN(readw, u16)
> DEF_IO_IN(readl, u32)
> DEF_IO_IN(readq, u64)
> DEF_IO_OUT(outb, u8)
> DEF_IO_OUT(outw, u16)
> DEF_IO_OUT(outl, u32)
> DEF_IO_OUT(outq, u64)
> DEF_IO_IN(inb, u8)
> DEF_IO_IN(inw, u16)
> DEF_IO_IN(inl, u32)
> DEF_IO_IN(inq, u64)
Overall, I still prefer my version :-)
Another thing I can do is to have an io_defs.h that contains basically
a list of all of them:
PCI_IO_DEF(writeb, u8, MMIO, OUT)
PCI_IO_DEF(writew, u16, MMIO, OUT)
.../...
And then have the various .h and .c files #include that file after
#defining PCI_IO_DEF to different things.
Thus we could have that file included twice: once for the struct
definiction ppc_io that includes them to define the callbacks and once
to implement the inline accessors.
If the callbacks are in a struct, I don't have to implement them all
separately and EXPORT_SYMBOL each of them.
Ben.
^ permalink raw reply
* Re: [patch 08/16] powerpc: remove EMBEDDED6xx Kconfig entry
From: Josh Boyer @ 2006-11-04 1:41 UTC (permalink / raw)
To: Olof Johansson; +Cc: paulus, linuxppc-dev
In-Reply-To: <20061103174948.34a5afe4@localhost.localdomain>
On Fri, 2006-11-03 at 17:49 -0600, Olof Johansson wrote:
> On Sat, 04 Nov 2006 08:32:14 +1100 Benjamin Herrenschmidt <benh@kernel.crashing.org> wrote:
>
> > But that's not a public/opensource thing people use regulary is it ?
>
> Might not be. I don't know what AMCC use for their eval boards, if it's
> u-boot or PIBS or something else.
AMCC uses u-boot on their new boards. Some of their older ones used
PIBS.
PIBS does have an open source type license. You can download it as part
of the PPC 970FX eval kit. Or other eval kits for various boards.
josh
^ permalink raw reply
* Re: [patch 08/16] powerpc: remove EMBEDDED6xx Kconfig entry
From: Wolfgang Denk @ 2006-11-04 2:07 UTC (permalink / raw)
To: Olof Johansson; +Cc: paulus, linuxppc-dev
In-Reply-To: <20061103174948.34a5afe4@localhost.localdomain>
In message <20061103174948.34a5afe4@localhost.localdomain> you wrote:
>
> Might not be. I don't know what AMCC use for their eval boards, if it's
> u-boot or PIBS or something else.
There is a working U-Boot configuration for all AMCC eval boards
(including downloadable binary images). So if you want, you can use
U-Boot on all these boards.
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
It is impractical for the standard to attempt to constrain the
behavior of code that does not obey the constraints of the standard.
- Doug Gwyn
^ 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