* Re: [RFC] Inter-processor Mailboxes Drivers
From: Sundar @ 2011-02-12 6:28 UTC (permalink / raw)
To: Meador Inge
Cc: Linus WALLEIJ, Hiroshi DOYU, Blanchard, Hollis, openmcapi-dev,
linuxppc-dev, linux-arm-kernel
In-Reply-To: <4D55A7F7.5090700@mentor.com>
Hi,
On Sat, Feb 12, 2011 at 2:49 AM, Meador Inge <meador_inge@mentor.com> wrote=
:
>
> =A0 =A01. Hardware specific bits somewhere under '.../arch/*'. =A0Drivers
> =A0 =A0 =A0 for the MPIC message registers on Power and OMAP4 mailboxes, =
for
> =A0 =A0 =A0 example.
Yes; this can help.
> =A0 =A02. A higher level driver under '.../drivers/mailbox/*'. =A0That th=
e
> =A0 =A0 =A0 pieces in (1) would register with. =A0This piece would expose=
the
> =A0 =A0 =A0 main kernel API.
A lot of mailboxes are too platform specific with regards to the communicat=
ion
with the main CPU and probably it depends on the mailbox too; you can
find polling and
interrupt supported mailbox support at times on the same platform.
APIs should probably be
generic enough to be able to operate in any context.
> Now I have the following questions:
>
> =A0 =A01. Do others see value in this?
At least I would like this; I wanted to generalize such mailbox IPCs
right from the
day when I was working on one, but coudnt really work on that.
> =A0 =A02. Does something like this already exist?
Not generic as you say; but apart from the OMAP platforms,
you could refer to arch/arm/mach-ux500/prcmu for a mailbox based
IPC on the U8500 platform.
> =A0 =A03. Is someone else already working on this?
Not sure of that too :), but I am CCing Linus W, the maintainer
of U8500 if he thinks it is a good idea to come up with a mailbox IPC
framework
Cheers!
--=20
---------
The views expressed in this email are personal and do not necessarily
echo my employers.
^ permalink raw reply
* arch/powerpc/kernel/cacheinfo.c: Possible null pointer dereference
From: David Binderman @ 2011-02-12 10:08 UTC (permalink / raw)
To: benh, paulus; +Cc: linuxppc-dev
[-- Attachment #1: Type: text/plain, Size: 538 bytes --]
Hello there,
I just tried out cppcheck-1.47 on the linux-2.6.38-rc4 source code.
It said
[arch/powerpc/kernel/cacheinfo.c:380]: (error) Possible null pointer dereference: cache - otherwise it is redundant to check if cache is null at line 382
The source code is
WARN_ONCE(cache && cache->level != level,
"cache level mismatch on lookup (got %d, expected %d)\n",
cache->level, level);
if (!cache)
I agree with cppcheck. Suggest code rework.
Regards
David Binderman
[-- Attachment #2: Type: text/html, Size: 913 bytes --]
^ permalink raw reply
* [git pull] Documentation changes and an SPI bug fix
From: Grant Likely @ 2011-02-13 15:15 UTC (permalink / raw)
To: Linux Kernel Mailing List, Linus Torvalds
Cc: spi-devel-general, devicetree-discuss, Guennadi Liakhovetski,
linuxppc-dev
In-Reply-To: <AANLkTikM0bZbRfSPeXjf4NVn_AAHm1w7FWRKYvoucdHj@mail.gmail.com>
[-- Attachment #1: Type: text/plain, Size: 9451 bytes --]
Hi Linus,
A set of mostly documentation changes, but I also had an spi bug fix that I
needed to send to you, so I've sent it all in one pull req.
g.
The following changes since commit d2478521afc20227658a10a8c5c2bf1a2aa615b3:
char/ipmi: fix OOPS caused by pnp_unregister_driver on unregistered driver
(2011-02-10 18:00:21 -0800)
are available in the git repository at:
git://git.secretlab.ca/git/linux-2.6 spi/merge
Grant Likely (5):
dt: Move device tree documentation out of powerpc directory
dt: Remove obsolete description of powerpc boot interface
dt: add documentation of ARM dt boot interface
MAINTAINERS: Add entry for GPIO subsystem
Merge branch 'devicetree/merge' into spi/merge
Guennadi Liakhovetski (1):
spi/spi_sh_msiof: fix wrong address calculation, which leads to an Oops
Paul Bolle (1):
devicetree-discuss is moderated for non-subscribers
Documentation/arm/Booting | 33 +++-
.../bindings/ata/fsl-sata.txt} | 0
.../bindings}/eeprom.txt | 0
.../fsl => devicetree/bindings/gpio}/8xxx_gpio.txt | 0
.../bindings}/gpio/gpio.txt | 0
.../bindings}/gpio/led.txt | 0
.../bindings/i2c/fsl-i2c.txt} | 0
.../bindings}/marvell.txt | 0
.../bindings/mmc/fsl-esdhc.txt} | 0
.../bindings/mmc}/mmc-spi-slot.txt | 0
.../bindings/mtd/fsl-upm-nand.txt} | 0
.../bindings/mtd}/mtd-physmap.txt | 0
.../bindings/net/can/mpc5xxx-mscan.txt} | 0
.../bindings/net}/can/sja1000.txt | 0
.../bindings/net/fsl-tsec-phy.txt} | 0
.../bindings/net/mdio-gpio.txt} | 0
.../bindings/net}/phy.txt | 0
.../bindings/pci}/83xx-512x-pci.txt | 0
.../bindings/powerpc}/4xx/cpm.txt | 0
.../bindings/powerpc}/4xx/emac.txt | 0
.../bindings/powerpc}/4xx/ndfc.txt | 0
.../bindings/powerpc}/4xx/ppc440spe-adma.txt | 0
.../bindings/powerpc}/4xx/reboot.txt | 0
.../bindings/powerpc}/fsl/board.txt | 0
.../bindings/powerpc}/fsl/cpm_qe/cpm.txt | 0
.../bindings/powerpc}/fsl/cpm_qe/cpm/brg.txt | 0
.../bindings/powerpc}/fsl/cpm_qe/cpm/i2c.txt | 0
.../bindings/powerpc}/fsl/cpm_qe/cpm/pic.txt | 0
.../bindings/powerpc}/fsl/cpm_qe/cpm/usb.txt | 0
.../bindings/powerpc}/fsl/cpm_qe/gpio.txt | 0
.../bindings/powerpc}/fsl/cpm_qe/network.txt | 0
.../bindings/powerpc}/fsl/cpm_qe/qe.txt | 0
.../bindings/powerpc}/fsl/cpm_qe/qe/firmware.txt | 0
.../bindings/powerpc}/fsl/cpm_qe/qe/par_io.txt | 0
.../bindings/powerpc}/fsl/cpm_qe/qe/pincfg.txt | 0
.../bindings/powerpc}/fsl/cpm_qe/qe/ucc.txt | 0
.../bindings/powerpc}/fsl/cpm_qe/qe/usb.txt | 0
.../bindings/powerpc}/fsl/cpm_qe/serial.txt | 0
.../bindings/powerpc}/fsl/diu.txt | 0
.../bindings/powerpc}/fsl/dma.txt | 0
.../bindings/powerpc/fsl}/ecm.txt | 0
.../bindings/powerpc}/fsl/gtm.txt | 0
.../bindings/powerpc}/fsl/guts.txt | 0
.../bindings/powerpc}/fsl/lbc.txt | 0
.../bindings/powerpc}/fsl/mcm.txt | 0
.../bindings/powerpc}/fsl/mcu-mpc8349emitx.txt | 0
.../bindings/powerpc}/fsl/mpc5121-psc.txt | 0
.../bindings/powerpc}/fsl/mpc5200.txt | 0
.../bindings/powerpc}/fsl/mpic.txt | 0
.../bindings/powerpc}/fsl/msi-pic.txt | 0
.../bindings/powerpc}/fsl/pmc.txt | 0
.../bindings/powerpc}/fsl/sec.txt | 0
.../bindings/powerpc}/fsl/ssi.txt | 0
.../bindings/powerpc}/nintendo/gamecube.txt | 0
.../bindings/powerpc}/nintendo/wii.txt | 0
.../bindings/spi/fsl-spi.txt} | 0
.../bindings/spi}/spi-bus.txt | 0
.../bindings/usb/fsl-usb.txt} | 0
.../bindings/usb}/usb-ehci.txt | 0
.../bindings}/xilinx.txt | 0
.../{powerpc => devicetree}/booting-without-of.txt | 193
+++++++++-----------
MAINTAINERS | 11 +-
drivers/spi/spi_sh_msiof.c | 6 +-
63 files changed, 131 insertions(+), 112 deletions(-)
rename Documentation/{powerpc/dts-bindings/fsl/sata.txt =>
devicetree/bindings/ata/fsl-sata.txt} (100%)
rename Documentation/{powerpc/dts-bindings =>
devicetree/bindings}/eeprom.txt (100%)
rename Documentation/{powerpc/dts-bindings/fsl =>
devicetree/bindings/gpio}/8xxx_gpio.txt (100%)
rename Documentation/{powerpc/dts-bindings =>
devicetree/bindings}/gpio/gpio.txt (100%)
rename Documentation/{powerpc/dts-bindings =>
devicetree/bindings}/gpio/led.txt (100%)
rename Documentation/{powerpc/dts-bindings/fsl/i2c.txt =>
devicetree/bindings/i2c/fsl-i2c.txt} (100%)
rename Documentation/{powerpc/dts-bindings =>
devicetree/bindings}/marvell.txt (100%)
rename Documentation/{powerpc/dts-bindings/fsl/esdhc.txt =>
devicetree/bindings/mmc/fsl-esdhc.txt} (100%)
rename Documentation/{powerpc/dts-bindings =>
devicetree/bindings/mmc}/mmc-spi-slot.txt (100%)
rename Documentation/{powerpc/dts-bindings/fsl/upm-nand.txt =>
devicetree/bindings/mtd/fsl-upm-nand.txt} (100%)
rename Documentation/{powerpc/dts-bindings =>
devicetree/bindings/mtd}/mtd-physmap.txt (100%)
rename Documentation/{powerpc/dts-bindings/fsl/can.txt =>
devicetree/bindings/net/can/mpc5xxx-mscan.txt} (100%)
rename Documentation/{powerpc/dts-bindings =>
devicetree/bindings/net}/can/sja1000.txt (100%)
rename Documentation/{powerpc/dts-bindings/fsl/tsec.txt =>
devicetree/bindings/net/fsl-tsec-phy.txt} (100%)
rename Documentation/{powerpc/dts-bindings/gpio/mdio.txt =>
devicetree/bindings/net/mdio-gpio.txt} (100%)
rename Documentation/{powerpc/dts-bindings =>
devicetree/bindings/net}/phy.txt (100%)
rename Documentation/{powerpc/dts-bindings/fsl =>
devicetree/bindings/pci}/83xx-512x-pci.txt (100%)
rename Documentation/{powerpc/dts-bindings =>
devicetree/bindings/powerpc}/4xx/cpm.txt (100%)
rename Documentation/{powerpc/dts-bindings =>
devicetree/bindings/powerpc}/4xx/emac.txt (100%)
rename Documentation/{powerpc/dts-bindings =>
devicetree/bindings/powerpc}/4xx/ndfc.txt (100%)
rename Documentation/{powerpc/dts-bindings =>
devicetree/bindings/powerpc}/4xx/ppc440spe-adma.txt (100%)
rename Documentation/{powerpc/dts-bindings =>
devicetree/bindings/powerpc}/4xx/reboot.txt (100%)
rename Documentation/{powerpc/dts-bindings =>
devicetree/bindings/powerpc}/fsl/board.txt (100%)
rename Documentation/{powerpc/dts-bindings =>
devicetree/bindings/powerpc}/fsl/cpm_qe/cpm.txt (100%)
rename Documentation/{powerpc/dts-bindings =>
devicetree/bindings/powerpc}/fsl/cpm_qe/cpm/brg.txt (100%)
rename Documentation/{powerpc/dts-bindings =>
devicetree/bindings/powerpc}/fsl/cpm_qe/cpm/i2c.txt (100%)
rename Documentation/{powerpc/dts-bindings =>
devicetree/bindings/powerpc}/fsl/cpm_qe/cpm/pic.txt (100%)
rename Documentation/{powerpc/dts-bindings =>
devicetree/bindings/powerpc}/fsl/cpm_qe/cpm/usb.txt (100%)
rename Documentation/{powerpc/dts-bindings =>
devicetree/bindings/powerpc}/fsl/cpm_qe/gpio.txt (100%)
rename Documentation/{powerpc/dts-bindings =>
devicetree/bindings/powerpc}/fsl/cpm_qe/network.txt (100%)
rename Documentation/{powerpc/dts-bindings =>
devicetree/bindings/powerpc}/fsl/cpm_qe/qe.txt (100%)
rename Documentation/{powerpc/dts-bindings =>
devicetree/bindings/powerpc}/fsl/cpm_qe/qe/firmware.txt (100%)
rename Documentation/{powerpc/dts-bindings =>
devicetree/bindings/powerpc}/fsl/cpm_qe/qe/par_io.txt (100%)
rename Documentation/{powerpc/dts-bindings =>
devicetree/bindings/powerpc}/fsl/cpm_qe/qe/pincfg.txt (100%)
rename Documentation/{powerpc/dts-bindings =>
devicetree/bindings/powerpc}/fsl/cpm_qe/qe/ucc.txt (100%)
rename Documentation/{powerpc/dts-bindings =>
devicetree/bindings/powerpc}/fsl/cpm_qe/qe/usb.txt (100%)
rename Documentation/{powerpc/dts-bindings =>
devicetree/bindings/powerpc}/fsl/cpm_qe/serial.txt (100%)
rename Documentation/{powerpc/dts-bindings =>
devicetree/bindings/powerpc}/fsl/diu.txt (100%)
rename Documentation/{powerpc/dts-bindings =>
devicetree/bindings/powerpc}/fsl/dma.txt (100%)
rename Documentation/{powerpc/dts-bindings =>
devicetree/bindings/powerpc/fsl}/ecm.txt (100%)
rename Documentation/{powerpc/dts-bindings =>
devicetree/bindings/powerpc}/fsl/gtm.txt (100%)
rename Documentation/{powerpc/dts-bindings =>
devicetree/bindings/powerpc}/fsl/guts.txt (100%)
rename Documentation/{powerpc/dts-bindings =>
devicetree/bindings/powerpc}/fsl/lbc.txt (100%)
rename Documentation/{powerpc/dts-bindings =>
devicetree/bindings/powerpc}/fsl/mcm.txt (100%)
rename Documentation/{powerpc/dts-bindings =>
devicetree/bindings/powerpc}/fsl/mcu-mpc8349emitx.txt (100%)
rename Documentation/{powerpc/dts-bindings =>
devicetree/bindings/powerpc}/fsl/mpc5121-psc.txt (100%)
rename Documentation/{powerpc/dts-bindings =>
devicetree/bindings/powerpc}/fsl/mpc5200.txt (100%)
rename Documentation/{powerpc/dts-bindings =>
devicetree/bindings/powerpc}/fsl/mpic.txt (100%)
rename Documentation/{powerpc/dts-bindings =>
devicetree/bindings/powerpc}/fsl/msi-pic.txt (100%)
rename Documentation/{powerpc/dts-bindings =>
devicetree/bindings/powerpc}/fsl/pmc.txt (100%)
rename Documentation/{powerpc/dts-bindings =>
devicetree/bindings/powerpc}/fsl/sec.txt (100%)
rename Documentation/{powerpc/dts-bindings =>
devicetree/bindings/powerpc}/fsl/ssi.txt (100%)
rename Documentation/{powerpc/dts-bindings =>
devicetree/bindings/powerpc}/nintendo/gamecube.txt (100%)
rename Documentation/{powerpc/dts-bindings =>
devicetree/bindings/powerpc}/nintendo/wii.txt (100%)
rename Documentation/{powerpc/dts-bindings/fsl/spi.txt =>
devicetree/bindings/spi/fsl-spi.txt} (100%)
rename Documentation/{powerpc/dts-bindings =>
devicetree/bindings/spi}/spi-bus.txt (100%)
rename Documentation/{powerpc/dts-bindings/fsl/usb.txt =>
devicetree/bindings/usb/fsl-usb.txt} (100%)
rename Documentation/{powerpc/dts-bindings =>
devicetree/bindings/usb}/usb-ehci.txt (100%)
rename Documentation/{powerpc/dts-bindings =>
devicetree/bindings}/xilinx.txt (100%)
rename Documentation/{powerpc => devicetree}/booting-without-of.txt (90%)
--
Grant Likely, B.Sc., P.Eng.
Secret Lab Technologies Ltd.
[-- Attachment #2: Type: text/html, Size: 10304 bytes --]
^ permalink raw reply
* Re: [RFC] Inter-processor Mailboxes Drivers
From: Linus Walleij @ 2011-02-13 21:16 UTC (permalink / raw)
To: Sundar
Cc: Meador Inge, Hiroshi DOYU, Blanchard, Hollis, openmcapi-dev,
linuxppc-dev, linux-arm-kernel
In-Reply-To: <AANLkTikP0P9S1VgiU_yT53f-kZq0JMLBJoVWigAy8YWB@mail.gmail.com>
2011/2/12 Sundar <sunder.svit@gmail.com>:
> At least I would like this; I wanted to generalize such mailbox IPCs
> right from the day when I was working on one, but coudnt really
> work on that.
>
>> =A0 =A02. Does something like this already exist?
>
> Not generic as you say; but apart from the OMAP platforms,
> you could refer to arch/arm/mach-ux500/prcmu for a mailbox based
> IPC on the U8500 platform.
We also have this thing:
arch/arm/mach-ux500/mbox-db5500.c
It's another mailbox driver, this one talks to the modem in the
U5500 (basically a physical transport for the CAIF protocol).
(For the U8500 I think modem IPC is instead handled with
a high-speed hardware FIFO, a bit different.)
>> =A0 =A03. Is someone else already working on this?
>
> Not sure of that too :), but I am CCing Linus W, the maintainer
> of U8500 if he thinks it is a good idea to come up with a mailbox IPC
> framework
I don't know too much about the subject actually, I've not been
deeply into any such code. I don't think anyone is working
on something general from ST-Ericsson or Linaro.
Recently I saw that Texas Instruments are posting a "hardware
spinlock" framework though, this would be on a related tone,
but I think it's for shared data structures (control path) rather
than buffer passing (data path). I'm guessing this works like
that one CPU gets to spin waiting for another one to release
the lock.
Given that we may have a framework for hardware spinlock
and that we don't want to stockpile drivers into arch/*
or drivers/misc/* I would say it's intuitively a good idea,
but the question is what data types you would pass in?
In arch/arm/mach-ux500/include/mach/mbox-db5500.h
we have a struct like this:
/**
* struct mbox - Mailbox instance struct
* @list: Linked list head.
* @pdev: Pointer to device struct.
* @cb: Callback function. Will be called
* when new data is received.
* @client_data: Clients private data. Will be sent back
* in the callback function.
* @virtbase_peer: Virtual address for outgoing mailbox.
* @virtbase_local: Virtual address for incoming mailbox.
* @buffer: Then internal queue for outgoing messages.
* @name: Name of this mailbox.
* @buffer_available: Completion variable to achieve "blocking send".
* This variable will be signaled when there is
* internal buffer space available.
* @client_blocked: To keep track if any client is currently
* blocked.
* @lock: Spinlock to protect this mailbox instance.
* @write_index: Index in internal buffer to write to.
* @read_index: Index in internal buffer to read from.
* @allocated: Indicates whether this particular mailbox
* id has been allocated by someone.
*/
struct mbox {
struct list_head list;
struct platform_device *pdev;
mbox_recv_cb_t *cb;
void *client_data;
void __iomem *virtbase_peer;
void __iomem *virtbase_local;
u32 buffer[MBOX_BUF_SIZE];
char name[MBOX_NAME_SIZE];
struct completion buffer_available;
u8 client_blocked;
spinlock_t lock;
u8 write_index;
u8 read_index;
bool allocated;
};
Compare OMAPs mailboxes in
arch/arm/plat-omap/include/plat/mailbox.h:
typedef u32 mbox_msg_t;
truct omap_mbox_ops {
omap_mbox_type_t type;
int (*startup)(struct omap_mbox *mbox);
void (*shutdown)(struct omap_mbox *mbox);
/* fifo */
mbox_msg_t (*fifo_read)(struct omap_mbox *mbox);
void (*fifo_write)(struct omap_mbox *mbox, mbox_msg_t ms=
g);
int (*fifo_empty)(struct omap_mbox *mbox);
int (*fifo_full)(struct omap_mbox *mbox);
/* irq */
void (*enable_irq)(struct omap_mbox *mbox,
omap_mbox_irq_t irq);
void (*disable_irq)(struct omap_mbox *mbox,
omap_mbox_irq_t irq);
void (*ack_irq)(struct omap_mbox *mbox, omap_mbox_irq_t =
irq);
int (*is_irq)(struct omap_mbox *mbox, omap_mbox_irq_t i=
rq);
/* ctx */
void (*save_ctx)(struct omap_mbox *mbox);
void (*restore_ctx)(struct omap_mbox *mbox);
};
struct omap_mbox_queue {
spinlock_t lock;
struct kfifo fifo;
struct work_struct work;
struct tasklet_struct tasklet;
struct omap_mbox *mbox;
bool full;
};
struct omap_mbox {
char *name;
unsigned int irq;
struct omap_mbox_queue *txq, *rxq;
struct omap_mbox_ops *ops;
struct device *dev;
void *priv;
int use_count;
struct blocking_notifier_head notifier;
};
Some of this may be generalized? I dunno, they look quite
different but maybe queueing etc can actually be made general
enough to form a framework.
Yours,
Linus Walleij
^ permalink raw reply
* Re: [RFC] Inter-processor Mailboxes Drivers
From: Linus Walleij @ 2011-02-13 21:24 UTC (permalink / raw)
To: Meador Inge
Cc: openmcapi-dev, Blanchard, Hollis, Hiroshi DOYU, linuxppc-dev,
linux-arm-kernel
In-Reply-To: <4D55A7F7.5090700@mentor.com>
2011/2/11 Meador Inge <meador_inge@mentor.com>:
>=A0This would entail the traditional
> generic/specific driver split:
>
> =A0 =A01. Hardware specific bits somewhere under '.../arch/*'. =A0Drivers
> =A0 =A0 =A0 for the MPIC message registers on Power and OMAP4 mailboxes, =
for
> =A0 =A0 =A0 example.
Having any drivers under arch/* is no good tradition IMO.
Better move the whole shebang down to drivers/mailbox so
that the subsystem maintainer get the complete overview
of her/his driver family.
> =A0 =A02. A higher level driver under '.../drivers/mailbox/*'. =A0That th=
e
> =A0 =A0 =A0 pieces in (1) would register with. =A0This piece would expose=
the
> =A0 =A0 =A0 main kernel API.
Cool...
> =A0 =A03. Userspace interfaces for accessing the mailboxes. =A0A
> =A0 =A0 =A0 '/dev/mailbox1', '/dev/mailbox2', etc... mapping, for example=
.
What kind of business does userspace have with directly using
mailboxes? Enlighten me so I get it... in our system these are
used by protocols, such as net/caif/* thru drivers/net/caif/*, and
we have similar kernelspace functionality for Phonet.
CAIF and Phonet on the other hand, have custom openings
down to the thing that exists on the other end of the mailbox.
Most of these systems tend to talk some funny protocol that
is often better handled by the kernel than by any userspace.
So is this for the situation when you have no intermediate
protocol between your userpace and the other CPU's
subsystem? Or are you thinking about handling that
protocol in userspace? That is generally not such a good idea
for efficiency reasons.
Yoursm
Linus Walleij
^ permalink raw reply
* Re: arch/powerpc/kernel/cacheinfo.c: Possible null pointer dereference
From: Michael Ellerman @ 2011-02-13 23:24 UTC (permalink / raw)
To: David Binderman; +Cc: paulus, linuxppc-dev
In-Reply-To: <BLU154-w1013E8541813DF8B7564CD9CEE0@phx.gbl>
[-- Attachment #1: Type: text/plain, Size: 861 bytes --]
On Sat, 2011-02-12 at 10:08 +0000, David Binderman wrote:
> Hello there,
>
> I just tried out cppcheck-1.47 on the linux-2.6.38-rc4 source code.
>
> It said
>
> [arch/powerpc/kernel/cacheinfo.c:380]: (error) Possible null pointer
> dereference: cache - otherwise it is redundant to check if cache is
> null at line 382
>
> The source code is
>
> WARN_ONCE(cache && cache->level != level,
> "cache level mismatch on lookup (got %d, expected %d)\n",
> cache->level, level);
>
> if (!cache)
>
> I agree with cppcheck. Suggest code rework.
It's wrong.
The code is essentially:
if (cache && cache->level != level)
printf("cache level mismatch on lookup (got %d, expected %d)\n", cache->level, level);
if (!cache)
cache = cache_do_one_devnode(node, level);
Which looks fine to me?
cheers
[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 198 bytes --]
^ permalink raw reply
* Re: Resources used by driver ?
From: Michael Ellerman @ 2011-02-13 23:38 UTC (permalink / raw)
To: Guillaume Dargaud; +Cc: LinuxPPC-dev
In-Reply-To: <201102101108.47647.dargaud@lpsc.in2p3.fr>
[-- Attachment #1: Type: text/plain, Size: 983 bytes --]
On Thu, 2011-02-10 at 11:08 +0100, Guillaume Dargaud wrote:
> Thanks to the advice I received here, I now have my first 'real' Linux driver
> up and running and am now at the optimization stage.
>
> Is it possible to see the resources consumed by a module ? They don't show in
> 'ps/top' but I'm sure there are ways to see how much memory it uses (to check
> for memory leaks) and how much CPU it takes. How ?
Hi Guillaume,
It's actually not that easy to measure the resources used by a driver.
In general your driver code only runs on behalf of another process, and
so that process is where the cpu usage will be accounted.
One exception is if your driver spawns a kernel thread for something, in
that case you can see it with top.
For memory usage, you can monitor /proc/slabinfo and see if anything is
growing every time you access your driver. Another option is to enable
CONFIG_DEBUG_KMEMLEAK, which will try and detect real leaks for you.
cheers
[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 198 bytes --]
^ permalink raw reply
* [git pull] Documentation changes and an SPI bug fix
From: Grant Likely @ 2011-02-14 3:46 UTC (permalink / raw)
To: Linux Kernel Mailing List, Linus Torvalds
Cc: spi-devel-general, devicetree-discuss, Guennadi Liakhovetski,
linuxppc-dev
In-Reply-To: <AANLkTikpR4191DrgyodXV-Qx=r8mjXziknzJ8tJpgBt9@mail.gmail.com>
[Resend: Android insisted on sending HTML, so it was rejected by LKML]
Hi Linus,
A set of mostly documentation changes, but I also had an spi bug fix
that I needed to send to you, so I've sent it all in one pull req.
g.
The following changes since commit d2478521afc20227658a10a8c5c2bf1a2aa615b3:
char/ipmi: fix OOPS caused by pnp_unregister_driver on unregistered
driver (2011-02-10 18:00:21 -0800)
are available in the git repository at:
git://git.secretlab.ca/git/linux-2.6 spi/merge
Grant Likely (5):
dt: Move device tree documentation out of powerpc directory
dt: Remove obsolete description of powerpc boot interface
dt: add documentation of ARM dt boot interface
MAINTAINERS: Add entry for GPIO subsystem
Merge branch 'devicetree/merge' into spi/merge
Guennadi Liakhovetski (1):
spi/spi_sh_msiof: fix wrong address calculation, which leads to an Oops
Paul Bolle (1):
devicetree-discuss is moderated for non-subscribers
Documentation/arm/Booting | 33 +++-
.../bindings/ata/fsl-sata.txt} | 0
.../bindings}/eeprom.txt | 0
.../fsl => devicetree/bindings/gpio}/8xxx_gpio.txt | 0
.../bindings}/gpio/gpio.txt | 0
.../bindings}/gpio/led.txt | 0
.../bindings/i2c/fsl-i2c.txt} | 0
.../bindings}/marvell.txt | 0
.../bindings/mmc/fsl-esdhc.txt} | 0
.../bindings/mmc}/mmc-spi-slot.txt | 0
.../bindings/mtd/fsl-upm-nand.txt} | 0
.../bindings/mtd}/mtd-physmap.txt | 0
.../bindings/net/can/mpc5xxx-mscan.txt} | 0
.../bindings/net}/can/sja1000.txt | 0
.../bindings/net/fsl-tsec-phy.txt} | 0
.../bindings/net/mdio-gpio.txt} | 0
.../bindings/net}/phy.txt | 0
.../bindings/pci}/83xx-512x-pci.txt | 0
.../bindings/powerpc}/4xx/cpm.txt | 0
.../bindings/powerpc}/4xx/emac.txt | 0
.../bindings/powerpc}/4xx/ndfc.txt | 0
.../bindings/powerpc}/4xx/ppc440spe-adma.txt | 0
.../bindings/powerpc}/4xx/reboot.txt | 0
.../bindings/powerpc}/fsl/board.txt | 0
.../bindings/powerpc}/fsl/cpm_qe/cpm.txt | 0
.../bindings/powerpc}/fsl/cpm_qe/cpm/brg.txt | 0
.../bindings/powerpc}/fsl/cpm_qe/cpm/i2c.txt | 0
.../bindings/powerpc}/fsl/cpm_qe/cpm/pic.txt | 0
.../bindings/powerpc}/fsl/cpm_qe/cpm/usb.txt | 0
.../bindings/powerpc}/fsl/cpm_qe/gpio.txt | 0
.../bindings/powerpc}/fsl/cpm_qe/network.txt | 0
.../bindings/powerpc}/fsl/cpm_qe/qe.txt | 0
.../bindings/powerpc}/fsl/cpm_qe/qe/firmware.txt | 0
.../bindings/powerpc}/fsl/cpm_qe/qe/par_io.txt | 0
.../bindings/powerpc}/fsl/cpm_qe/qe/pincfg.txt | 0
.../bindings/powerpc}/fsl/cpm_qe/qe/ucc.txt | 0
.../bindings/powerpc}/fsl/cpm_qe/qe/usb.txt | 0
.../bindings/powerpc}/fsl/cpm_qe/serial.txt | 0
.../bindings/powerpc}/fsl/diu.txt | 0
.../bindings/powerpc}/fsl/dma.txt | 0
.../bindings/powerpc/fsl}/ecm.txt | 0
.../bindings/powerpc}/fsl/gtm.txt | 0
.../bindings/powerpc}/fsl/guts.txt | 0
.../bindings/powerpc}/fsl/lbc.txt | 0
.../bindings/powerpc}/fsl/mcm.txt | 0
.../bindings/powerpc}/fsl/mcu-mpc8349emitx.txt | 0
.../bindings/powerpc}/fsl/mpc5121-psc.txt | 0
.../bindings/powerpc}/fsl/mpc5200.txt | 0
.../bindings/powerpc}/fsl/mpic.txt | 0
.../bindings/powerpc}/fsl/msi-pic.txt | 0
.../bindings/powerpc}/fsl/pmc.txt | 0
.../bindings/powerpc}/fsl/sec.txt | 0
.../bindings/powerpc}/fsl/ssi.txt | 0
.../bindings/powerpc}/nintendo/gamecube.txt | 0
.../bindings/powerpc}/nintendo/wii.txt | 0
.../bindings/spi/fsl-spi.txt} | 0
.../bindings/spi}/spi-bus.txt | 0
.../bindings/usb/fsl-usb.txt} | 0
.../bindings/usb}/usb-ehci.txt | 0
.../bindings}/xilinx.txt | 0
.../{powerpc => devicetree}/booting-without-of.txt | 193 +++++++++-----------
MAINTAINERS | 11 +-
drivers/spi/spi_sh_msiof.c | 6 +-
63 files changed, 131 insertions(+), 112 deletions(-)
rename Documentation/{powerpc/dts-bindings/fsl/sata.txt =>
devicetree/bindings/ata/fsl-sata.txt} (100%)
rename Documentation/{powerpc/dts-bindings =>
devicetree/bindings}/eeprom.txt (100%)
rename Documentation/{powerpc/dts-bindings/fsl =>
devicetree/bindings/gpio}/8xxx_gpio.txt (100%)
rename Documentation/{powerpc/dts-bindings =>
devicetree/bindings}/gpio/gpio.txt (100%)
rename Documentation/{powerpc/dts-bindings =>
devicetree/bindings}/gpio/led.txt (100%)
rename Documentation/{powerpc/dts-bindings/fsl/i2c.txt =>
devicetree/bindings/i2c/fsl-i2c.txt} (100%)
rename Documentation/{powerpc/dts-bindings =>
devicetree/bindings}/marvell.txt (100%)
rename Documentation/{powerpc/dts-bindings/fsl/esdhc.txt =>
devicetree/bindings/mmc/fsl-esdhc.txt} (100%)
rename Documentation/{powerpc/dts-bindings =>
devicetree/bindings/mmc}/mmc-spi-slot.txt (100%)
rename Documentation/{powerpc/dts-bindings/fsl/upm-nand.txt =>
devicetree/bindings/mtd/fsl-upm-nand.txt} (100%)
rename Documentation/{powerpc/dts-bindings =>
devicetree/bindings/mtd}/mtd-physmap.txt (100%)
rename Documentation/{powerpc/dts-bindings/fsl/can.txt =>
devicetree/bindings/net/can/mpc5xxx-mscan.txt} (100%)
rename Documentation/{powerpc/dts-bindings =>
devicetree/bindings/net}/can/sja1000.txt (100%)
rename Documentation/{powerpc/dts-bindings/fsl/tsec.txt =>
devicetree/bindings/net/fsl-tsec-phy.txt} (100%)
rename Documentation/{powerpc/dts-bindings/gpio/mdio.txt =>
devicetree/bindings/net/mdio-gpio.txt} (100%)
rename Documentation/{powerpc/dts-bindings =>
devicetree/bindings/net}/phy.txt (100%)
rename Documentation/{powerpc/dts-bindings/fsl =>
devicetree/bindings/pci}/83xx-512x-pci.txt (100%)
rename Documentation/{powerpc/dts-bindings =>
devicetree/bindings/powerpc}/4xx/cpm.txt (100%)
rename Documentation/{powerpc/dts-bindings =>
devicetree/bindings/powerpc}/4xx/emac.txt (100%)
rename Documentation/{powerpc/dts-bindings =>
devicetree/bindings/powerpc}/4xx/ndfc.txt (100%)
rename Documentation/{powerpc/dts-bindings =>
devicetree/bindings/powerpc}/4xx/ppc440spe-adma.txt (100%)
rename Documentation/{powerpc/dts-bindings =>
devicetree/bindings/powerpc}/4xx/reboot.txt (100%)
rename Documentation/{powerpc/dts-bindings =>
devicetree/bindings/powerpc}/fsl/board.txt (100%)
rename Documentation/{powerpc/dts-bindings =>
devicetree/bindings/powerpc}/fsl/cpm_qe/cpm.txt (100%)
rename Documentation/{powerpc/dts-bindings =>
devicetree/bindings/powerpc}/fsl/cpm_qe/cpm/brg.txt (100%)
rename Documentation/{powerpc/dts-bindings =>
devicetree/bindings/powerpc}/fsl/cpm_qe/cpm/i2c.txt (100%)
rename Documentation/{powerpc/dts-bindings =>
devicetree/bindings/powerpc}/fsl/cpm_qe/cpm/pic.txt (100%)
rename Documentation/{powerpc/dts-bindings =>
devicetree/bindings/powerpc}/fsl/cpm_qe/cpm/usb.txt (100%)
rename Documentation/{powerpc/dts-bindings =>
devicetree/bindings/powerpc}/fsl/cpm_qe/gpio.txt (100%)
rename Documentation/{powerpc/dts-bindings =>
devicetree/bindings/powerpc}/fsl/cpm_qe/network.txt (100%)
rename Documentation/{powerpc/dts-bindings =>
devicetree/bindings/powerpc}/fsl/cpm_qe/qe.txt (100%)
rename Documentation/{powerpc/dts-bindings =>
devicetree/bindings/powerpc}/fsl/cpm_qe/qe/firmware.txt (100%)
rename Documentation/{powerpc/dts-bindings =>
devicetree/bindings/powerpc}/fsl/cpm_qe/qe/par_io.txt (100%)
rename Documentation/{powerpc/dts-bindings =>
devicetree/bindings/powerpc}/fsl/cpm_qe/qe/pincfg.txt (100%)
rename Documentation/{powerpc/dts-bindings =>
devicetree/bindings/powerpc}/fsl/cpm_qe/qe/ucc.txt (100%)
rename Documentation/{powerpc/dts-bindings =>
devicetree/bindings/powerpc}/fsl/cpm_qe/qe/usb.txt (100%)
rename Documentation/{powerpc/dts-bindings =>
devicetree/bindings/powerpc}/fsl/cpm_qe/serial.txt (100%)
rename Documentation/{powerpc/dts-bindings =>
devicetree/bindings/powerpc}/fsl/diu.txt (100%)
rename Documentation/{powerpc/dts-bindings =>
devicetree/bindings/powerpc}/fsl/dma.txt (100%)
rename Documentation/{powerpc/dts-bindings =>
devicetree/bindings/powerpc/fsl}/ecm.txt (100%)
rename Documentation/{powerpc/dts-bindings =>
devicetree/bindings/powerpc}/fsl/gtm.txt (100%)
rename Documentation/{powerpc/dts-bindings =>
devicetree/bindings/powerpc}/fsl/guts.txt (100%)
rename Documentation/{powerpc/dts-bindings =>
devicetree/bindings/powerpc}/fsl/lbc.txt (100%)
rename Documentation/{powerpc/dts-bindings =>
devicetree/bindings/powerpc}/fsl/mcm.txt (100%)
rename Documentation/{powerpc/dts-bindings =>
devicetree/bindings/powerpc}/fsl/mcu-mpc8349emitx.txt (100%)
rename Documentation/{powerpc/dts-bindings =>
devicetree/bindings/powerpc}/fsl/mpc5121-psc.txt (100%)
rename Documentation/{powerpc/dts-bindings =>
devicetree/bindings/powerpc}/fsl/mpc5200.txt (100%)
rename Documentation/{powerpc/dts-bindings =>
devicetree/bindings/powerpc}/fsl/mpic.txt (100%)
rename Documentation/{powerpc/dts-bindings =>
devicetree/bindings/powerpc}/fsl/msi-pic.txt (100%)
rename Documentation/{powerpc/dts-bindings =>
devicetree/bindings/powerpc}/fsl/pmc.txt (100%)
rename Documentation/{powerpc/dts-bindings =>
devicetree/bindings/powerpc}/fsl/sec.txt (100%)
rename Documentation/{powerpc/dts-bindings =>
devicetree/bindings/powerpc}/fsl/ssi.txt (100%)
rename Documentation/{powerpc/dts-bindings =>
devicetree/bindings/powerpc}/nintendo/gamecube.txt (100%)
rename Documentation/{powerpc/dts-bindings =>
devicetree/bindings/powerpc}/nintendo/wii.txt (100%)
rename Documentation/{powerpc/dts-bindings/fsl/spi.txt =>
devicetree/bindings/spi/fsl-spi.txt} (100%)
rename Documentation/{powerpc/dts-bindings =>
devicetree/bindings/spi}/spi-bus.txt (100%)
rename Documentation/{powerpc/dts-bindings/fsl/usb.txt =>
devicetree/bindings/usb/fsl-usb.txt} (100%)
rename Documentation/{powerpc/dts-bindings =>
devicetree/bindings/usb}/usb-ehci.txt (100%)
rename Documentation/{powerpc/dts-bindings =>
devicetree/bindings}/xilinx.txt (100%)
rename Documentation/{powerpc => devicetree}/booting-without-of.txt (90%)
--
Grant Likely, B.Sc., P.Eng.
Secret Lab Technologies Ltd.
--
Grant Likely, B.Sc., P.Eng.
Secret Lab Technologies Ltd.
^ permalink raw reply
* [PATCH v2 3/3] tcm ibmvscsis driver
From: FUJITA Tomonori @ 2011-02-14 3:48 UTC (permalink / raw)
To: linux-scsi; +Cc: brking, linuxppc-dev, nab
This is the second version of tcm ibmvscsis driver. You can find the
first version at:
http://marc.info/?t=129734085600004&r=1&w=2
The changes are:
- send VIOSRP_MAD_NOT_SUPPORTED for unknown mad type requests.
- fix inquiry typo
- sends task management response (for now, 'NOT SUPPORTED').
- remove dead code.
=
From: FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp>
Subject: [PATCH v2 3/3] tcm ibmvscsis driver
This replaces ibmvstgt driver that uses the old target framework.
Signed-off-by: FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp>
---
drivers/scsi/ibmvscsi/Makefile | 4 +-
drivers/scsi/ibmvscsi/ibmvscsis.c | 1760 +++++++++++++++++++++++++++++++++++++
2 files changed, 1763 insertions(+), 1 deletions(-)
create mode 100644 drivers/scsi/ibmvscsi/ibmvscsis.c
diff --git a/drivers/scsi/ibmvscsi/Makefile b/drivers/scsi/ibmvscsi/Makefile
index a423d96..a615ea5 100644
--- a/drivers/scsi/ibmvscsi/Makefile
+++ b/drivers/scsi/ibmvscsi/Makefile
@@ -1,8 +1,10 @@
+EXTRA_CFLAGS += -I$(srctree)/drivers/target/
+
obj-$(CONFIG_SCSI_IBMVSCSI) += ibmvscsic.o
ibmvscsic-y += ibmvscsi.o
ibmvscsic-$(CONFIG_PPC_ISERIES) += iseries_vscsi.o
ibmvscsic-$(CONFIG_PPC_PSERIES) += rpa_vscsi.o
-obj-$(CONFIG_SCSI_IBMVSCSIS) += ibmvstgt.o
+obj-$(CONFIG_SCSI_IBMVSCSIS) += ibmvscsis.o
obj-$(CONFIG_SCSI_IBMVFC) += ibmvfc.o
diff --git a/drivers/scsi/ibmvscsi/ibmvscsis.c b/drivers/scsi/ibmvscsi/ibmvscsis.c
new file mode 100644
index 0000000..591cedb
--- /dev/null
+++ b/drivers/scsi/ibmvscsi/ibmvscsis.c
@@ -0,0 +1,1760 @@
+/*
+ * IBM eServer i/pSeries Virtual SCSI Target Driver
+ * Copyright (C) 2003-2005 Dave Boutcher (boutcher@us.ibm.com) IBM Corp.
+ * Santiago Leon (santil@us.ibm.com) IBM Corp.
+ * Linda Xie (lxie@us.ibm.com) IBM Corp.
+ *
+ * Copyright (C) 2005-2011 FUJITA Tomonori <tomof@acm.org>
+ * Copyright (C) 2010 Nicholas A. Bellinger <nab@kernel.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.
+ *
+ * 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/slab.h>
+#include <linux/kthread.h>
+#include <linux/types.h>
+#include <linux/list.h>
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/ctype.h>
+#include <linux/utsname.h>
+#include <asm/unaligned.h>
+#include <scsi/scsi.h>
+#include <scsi/scsi_host.h>
+#include <scsi/scsi_device.h>
+#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_tcq.h>
+#include <scsi/libsrp.h>
+#include <generated/utsrelease.h>
+
+#include <target/target_core_base.h>
+#include <target/target_core_transport.h>
+#include <target/target_core_fabric_ops.h>
+#include <target/target_core_fabric_lib.h>
+#include <target/target_core_fabric_configfs.h>
+#include <target/target_core_device.h>
+#include <target/target_core_tpg.h>
+#include <target/target_core_configfs.h>
+
+#include <asm/hvcall.h>
+#include <asm/iommu.h>
+#include <asm/prom.h>
+#include <asm/vio.h>
+
+#include "ibmvscsi.h"
+#include "viosrp.h"
+
+#define IBMVSCSIS_VERSION "v0.1"
+#define IBMVSCSIS_NAMELEN 32
+
+#define INITIAL_SRP_LIMIT 16
+#define DEFAULT_MAX_SECTORS 256
+
+/*
+ * Hypervisor calls.
+ */
+#define h_copy_rdma(l, sa, sb, da, db) \
+ plpar_hcall_norets(H_COPY_RDMA, l, sa, sb, da, db)
+#define h_send_crq(ua, l, h) \
+ plpar_hcall_norets(H_SEND_CRQ, ua, l, h)
+#define h_reg_crq(ua, tok, sz)\
+ plpar_hcall_norets(H_REG_CRQ, ua, tok, sz);
+#define h_free_crq(ua) \
+ plpar_hcall_norets(H_FREE_CRQ, ua);
+
+#define GETTARGET(x) ((int)((((u64)(x)) >> 56) & 0x003f))
+#define GETBUS(x) ((int)((((u64)(x)) >> 53) & 0x0007))
+#define GETLUN(x) ((int)((((u64)(x)) >> 48) & 0x001f))
+
+/*
+ * These are fixed for the system and come from the Open Firmware device tree.
+ * We just store them here to save getting them every time.
+ */
+static char system_id[64] = "";
+static char partition_name[97] = "UNKNOWN";
+static unsigned int partition_number = -1;
+
+static LIST_HEAD(tpg_list);
+static DEFINE_SPINLOCK(tpg_lock);
+
+struct ibmvscsis_adapter {
+ struct vio_dev *dma_dev;
+ struct list_head siblings;
+
+ struct crq_queue crq_queue;
+
+ struct work_struct crq_work;
+
+ unsigned long liobn;
+ unsigned long riobn;
+
+ /* todo: remove */
+ struct srp_target srpt;
+
+ /* SRP port target portal group tag for TCM */
+ unsigned long tport_tpgt;
+
+ /* Returned by ibmvscsis_make_tpg() */
+ struct se_portal_group se_tpg;
+
+ struct se_session *se_sess;
+
+
+ /* SCSI protocol the tport is providing */
+ u8 tport_proto_id;
+ /* Binary World Wide unique Port Name for SRP Target port */
+ u64 tport_wwpn;
+ /* ASCII formatted WWPN for SRP Target port */
+ char tport_name[IBMVSCSIS_NAMELEN];
+ /* Returned by ibmvscsis_make_tport() */
+ struct se_wwn tport_wwn;
+};
+
+struct ibmvscsis_cmnd {
+ /* Used for libsrp processing callbacks */
+ struct scsi_cmnd sc;
+ /* Used for TCM Core operations */
+ struct se_cmd se_cmd;
+ /* Sense buffer that will be mapped into outgoing status */
+ unsigned char sense_buf[TRANSPORT_SENSE_BUFFER];
+};
+
+static int ibmvscsis_check_true(struct se_portal_group *se_tpg)
+{
+ return 1;
+}
+
+static int ibmvscsis_check_false(struct se_portal_group *se_tpg)
+{
+ return 0;
+}
+
+static char *ibmvscsis_get_fabric_name(void)
+{
+ return "ibmvscsis";
+}
+
+static u8 ibmvscsis_get_fabric_proto_ident(struct se_portal_group *se_tpg)
+{
+ return 4;
+}
+
+static char *ibmvscsis_get_fabric_wwn(struct se_portal_group *se_tpg)
+{
+ struct ibmvscsis_adapter *adapter =
+ container_of(se_tpg, struct ibmvscsis_adapter, se_tpg);
+
+ return adapter->tport_name;
+}
+
+static u16 ibmvscsis_get_tag(struct se_portal_group *se_tpg)
+{
+ struct ibmvscsis_adapter *adapter =
+ container_of(se_tpg, struct ibmvscsis_adapter, se_tpg);
+ return adapter->tport_tpgt;
+}
+
+static u32 ibmvscsis_get_default_depth(struct se_portal_group *se_tpg)
+{
+ return 1;
+}
+
+/* we don't care about the transport id since we never use pr. */
+static u32 ibmvscsis_get_pr_transport_id(struct se_portal_group *se_tpg,
+ struct se_node_acl *se_nacl,
+ struct t10_pr_registration *pr_reg,
+ int *format_code,
+ unsigned char *buf)
+{
+ return 24;
+}
+
+static u32 ibmvscsis_get_pr_transport_id_len(struct se_portal_group *se_tpg,
+ struct se_node_acl *se_nacl,
+ struct t10_pr_registration *pr_reg,
+ int *format_code)
+{
+ return 24;
+}
+
+static char *ibmvscsis_parse_pr_out_transport_id(struct se_portal_group *se_tpg,
+ const char *buf,
+ u32 *out_tid_len,
+ char **port_nexus_ptr)
+{
+ return NULL;
+}
+
+struct ibmvscsis_nacl {
+ /* Binary World Wide unique Port Name for SRP Initiator port */
+ u64 iport_wwpn;
+ /* ASCII formatted WWPN for Sas Initiator port */
+ char iport_name[IBMVSCSIS_NAMELEN];
+ /* Returned by ibmvscsis_make_nodeacl() */
+ struct se_node_acl se_node_acl;
+};
+
+static struct se_node_acl *ibmvscsis_alloc_fabric_acl(struct se_portal_group *se_tpg)
+{
+ struct ibmvscsis_nacl *nacl;
+
+ nacl = kzalloc(sizeof(struct ibmvscsis_nacl), GFP_KERNEL);
+ if (!(nacl)) {
+ printk(KERN_ERR "Unable to alocate struct ibmvscsis_nacl\n");
+ return NULL;
+ }
+
+ return &nacl->se_node_acl;
+}
+
+static void ibmvscsis_release_fabric_acl(struct se_portal_group *se_tpg,
+ struct se_node_acl *se_nacl)
+{
+ struct ibmvscsis_nacl *nacl = container_of(se_nacl,
+ struct ibmvscsis_nacl, se_node_acl);
+ kfree(nacl);
+}
+
+static u32 ibmvscsis_tpg_get_inst_index(struct se_portal_group *se_tpg)
+{
+ return 1;
+}
+
+static void ibmvscsis_release_cmd(struct se_cmd *se_cmd)
+{
+ struct ibmvscsis_cmnd *cmd =
+ container_of(se_cmd, struct ibmvscsis_cmnd, se_cmd);
+ kfree(cmd);
+ return;
+}
+
+static int ibmvscsis_shutdown_session(struct se_session *se_sess)
+{
+ return 0;
+}
+
+static void ibmvscsis_close_session(struct se_session *se_sess)
+{
+ return;
+}
+
+static void ibmvscsis_stop_session(struct se_session *se_sess,
+ int sess_sleep , int conn_sleep)
+{
+ return;
+}
+
+static void ibmvscsis_reset_nexus(struct se_session *se_sess)
+{
+ return;
+}
+
+static int ibmvscsis_sess_logged_in(struct se_session *se_sess)
+{
+ return 0;
+}
+
+static u32 ibmvscsis_sess_get_index(struct se_session *se_sess)
+{
+ return 0;
+}
+
+static int ibmvscsis_write_pending_status(struct se_cmd *se_cmd)
+{
+ return 0;
+}
+
+static void ibmvscsis_set_default_node_attrs(struct se_node_acl *nacl)
+{
+ return;
+}
+
+static u32 ibmvscsis_get_task_tag(struct se_cmd *se_cmd)
+{
+ return 0;
+}
+
+static int ibmvscsis_get_cmd_state(struct se_cmd *se_cmd)
+{
+ return 0;
+}
+
+static void ibmvscsis_new_cmd_failure(struct se_cmd *se_cmd)
+{
+ return;
+}
+
+static int ibmvscsis_queue_tm_rsp(struct se_cmd *se_cmd)
+{
+ return 0;
+}
+
+static u16 ibmvscsis_set_fabric_sense_len(struct se_cmd *se_cmd,
+ u32 sense_length)
+{
+ return 0;
+}
+
+static u16 ibmvscsis_get_fabric_sense_len(void)
+{
+ return 0;
+}
+
+static int ibmvscsis_is_state_remove(struct se_cmd *se_cmd)
+{
+ return 0;
+}
+
+static u64 make_lun(unsigned int bus, unsigned int target, unsigned int lun);
+
+static u64 ibmvscsis_pack_lun(unsigned int lun)
+{
+ return make_lun(0, lun & 0x003f, 0);
+}
+
+/* Local pointer to allocated TCM configfs fabric module */
+static struct target_fabric_configfs *ibmvscsis_fabric_configfs;
+
+static struct se_portal_group *ibmvscsis_make_tpg(struct se_wwn *wwn,
+ struct config_group *group,
+ const char *name)
+{
+ struct ibmvscsis_adapter *adapter =
+ container_of(wwn, struct ibmvscsis_adapter, tport_wwn);
+ struct se_node_acl *acl;
+ int ret;
+ char *dname = (char *)dev_name(&adapter->dma_dev->dev);
+
+ if (strncmp(name, "tpgt_1", 6))
+ return ERR_PTR(-EINVAL);
+
+ ret = core_tpg_register(&ibmvscsis_fabric_configfs->tf_ops, wwn,
+ &adapter->se_tpg, (void *)adapter,
+ TRANSPORT_TPG_TYPE_NORMAL);
+ if (ret)
+ return ERR_PTR(-ENOMEM);
+
+ adapter->se_sess = transport_init_session();
+ if (!adapter->se_sess) {
+ core_tpg_deregister(&adapter->se_tpg);
+ return ERR_PTR(-ENOMEM);
+ }
+
+ acl = core_tpg_check_initiator_node_acl(&adapter->se_tpg, dname);
+ if (!acl) {
+ transport_free_session(adapter->se_sess);
+ adapter->se_sess = NULL;
+ return ERR_PTR(-ENOMEM);
+ }
+ adapter->se_sess->se_node_acl = acl;
+
+ transport_register_session(&adapter->se_tpg,
+ adapter->se_sess->se_node_acl,
+ adapter->se_sess, adapter);
+
+ return &adapter->se_tpg;
+}
+
+static void ibmvscsis_drop_tpg(struct se_portal_group *se_tpg)
+{
+ struct ibmvscsis_adapter *adapter =
+ container_of(se_tpg, struct ibmvscsis_adapter, se_tpg);
+ unsigned long flags;
+
+
+ transport_deregister_session_configfs(adapter->se_sess);
+ transport_free_session(adapter->se_sess);
+ core_tpg_deregister(se_tpg);
+
+ spin_lock_irqsave(&tpg_lock, flags);
+ adapter->se_sess = NULL;
+ spin_unlock_irqrestore(&tpg_lock, flags);
+}
+
+static struct se_wwn *ibmvscsis_make_tport(struct target_fabric_configfs *tf,
+ struct config_group *group,
+ const char *name)
+{
+ struct ibmvscsis_adapter *adapter;
+ unsigned long tpgt, flags;
+
+ if (strict_strtoul(name, 10, &tpgt))
+ return NULL;
+
+ spin_lock_irqsave(&tpg_lock, flags);
+ list_for_each_entry(adapter, &tpg_list, siblings) {
+ if (tpgt == adapter->tport_tpgt)
+ goto found;
+ }
+
+ spin_unlock_irqrestore(&tpg_lock, flags);
+ return NULL;
+found:
+ spin_unlock_irqrestore(&tpg_lock, flags);
+
+ return &adapter->tport_wwn;
+}
+
+static void ibmvscsis_drop_tport(struct se_wwn *wwn)
+{
+}
+
+static ssize_t ibmvscsis_wwn_show_attr_version(struct target_fabric_configfs *tf,
+ char *page)
+{
+ return sprintf(page, "IBMVSCSIS fabric module %s on %s/%s"
+ "on "UTS_RELEASE"\n", IBMVSCSIS_VERSION, utsname()->sysname,
+ utsname()->machine);
+}
+
+TF_WWN_ATTR_RO(ibmvscsis, version);
+
+static struct configfs_attribute *ibmvscsis_wwn_attrs[] = {
+ &ibmvscsis_wwn_version.attr,
+ NULL,
+};
+
+static int ibmvscsis_write_pending(struct se_cmd *se_cmd);
+static int ibmvscsis_queue_data_in(struct se_cmd *se_cmd);
+static int ibmvscsis_queue_status(struct se_cmd *se_cmd);
+static int ibmvscsis_new_cmd_map(struct se_cmd *se_cmd);
+static void ibmvscsis_check_stop_free(struct se_cmd *se_cmd);
+
+static struct target_core_fabric_ops ibmvscsis_ops = {
+ .task_sg_chaining = 1,
+ .get_fabric_name = ibmvscsis_get_fabric_name,
+ .get_fabric_proto_ident = ibmvscsis_get_fabric_proto_ident,
+ .tpg_get_wwn = ibmvscsis_get_fabric_wwn,
+ .tpg_get_tag = ibmvscsis_get_tag,
+ .tpg_get_default_depth = ibmvscsis_get_default_depth,
+ .tpg_get_pr_transport_id = ibmvscsis_get_pr_transport_id,
+ .tpg_get_pr_transport_id_len = ibmvscsis_get_pr_transport_id_len,
+ .tpg_parse_pr_out_transport_id = ibmvscsis_parse_pr_out_transport_id,
+ .tpg_check_demo_mode = ibmvscsis_check_true,
+ .tpg_check_demo_mode_cache = ibmvscsis_check_true,
+ .tpg_check_demo_mode_write_protect = ibmvscsis_check_false,
+ .tpg_check_prod_mode_write_protect = ibmvscsis_check_false,
+ .tpg_alloc_fabric_acl = ibmvscsis_alloc_fabric_acl,
+ .tpg_release_fabric_acl = ibmvscsis_release_fabric_acl,
+ .tpg_get_inst_index = ibmvscsis_tpg_get_inst_index,
+ .new_cmd_map = ibmvscsis_new_cmd_map,
+ .check_stop_free = ibmvscsis_check_stop_free,
+ .release_cmd_to_pool = ibmvscsis_release_cmd,
+ .release_cmd_direct = ibmvscsis_release_cmd,
+ .shutdown_session = ibmvscsis_shutdown_session,
+ .close_session = ibmvscsis_close_session,
+ .stop_session = ibmvscsis_stop_session,
+ .fall_back_to_erl0 = ibmvscsis_reset_nexus,
+ .sess_logged_in = ibmvscsis_sess_logged_in,
+ .sess_get_index = ibmvscsis_sess_get_index,
+ .sess_get_initiator_sid = NULL,
+ .write_pending = ibmvscsis_write_pending,
+ .write_pending_status = ibmvscsis_write_pending_status,
+ .set_default_node_attributes = ibmvscsis_set_default_node_attrs,
+ .get_task_tag = ibmvscsis_get_task_tag,
+ .get_cmd_state = ibmvscsis_get_cmd_state,
+ .new_cmd_failure = ibmvscsis_new_cmd_failure,
+ .queue_data_in = ibmvscsis_queue_data_in,
+ .queue_status = ibmvscsis_queue_status,
+ .queue_tm_rsp = ibmvscsis_queue_tm_rsp,
+ .get_fabric_sense_len = ibmvscsis_get_fabric_sense_len,
+ .set_fabric_sense_len = ibmvscsis_set_fabric_sense_len,
+ .is_state_remove = ibmvscsis_is_state_remove,
+ .pack_lun = ibmvscsis_pack_lun,
+ .fabric_make_wwn = ibmvscsis_make_tport,
+ .fabric_drop_wwn = ibmvscsis_drop_tport,
+ .fabric_make_tpg = ibmvscsis_make_tpg,
+ .fabric_drop_tpg = ibmvscsis_drop_tpg,
+ .fabric_post_link = NULL,
+ .fabric_pre_unlink = NULL,
+ .fabric_make_np = NULL,
+ .fabric_drop_np = NULL,
+ .fabric_make_nodeacl = NULL,
+ .fabric_drop_nodeacl = NULL,
+};
+
+static inline union viosrp_iu *vio_iu(struct iu_entry *iue)
+{
+ return (union viosrp_iu *)(iue->sbuf->buf);
+}
+
+static int send_iu(struct iu_entry *iue, u64 length, u8 format)
+{
+ struct srp_target *target = iue->target;
+ struct ibmvscsis_adapter *adapter = target->ldata;
+ long rc, rc1;
+ union {
+ struct viosrp_crq cooked;
+ u64 raw[2];
+ } crq;
+
+ /* First copy the SRP */
+ rc = h_copy_rdma(length, adapter->liobn, iue->sbuf->dma,
+ adapter->riobn, iue->remote_token);
+
+ if (rc)
+ printk(KERN_ERR "Error %ld transferring data\n", rc);
+
+ crq.cooked.valid = 0x80;
+ crq.cooked.format = format;
+ crq.cooked.reserved = 0x00;
+ crq.cooked.timeout = 0x00;
+ crq.cooked.IU_length = length;
+ crq.cooked.IU_data_ptr = vio_iu(iue)->srp.rsp.tag;
+
+ if (rc == 0)
+ crq.cooked.status = 0x99; /* Just needs to be non-zero */
+ else
+ crq.cooked.status = 0x00;
+
+ rc1 = h_send_crq(adapter->dma_dev->unit_address, crq.raw[0],
+ crq.raw[1]);
+ if (rc1) {
+ printk(KERN_ERR "%ld sending response\n", rc1);
+ return rc1;
+ }
+
+ return rc;
+}
+
+#define SRP_RSP_SENSE_DATA_LEN 18
+
+static int send_rsp(struct iu_entry *iue, struct scsi_cmnd *sc,
+ unsigned char status, unsigned char asc)
+{
+ union viosrp_iu *iu = vio_iu(iue);
+ uint64_t tag = iu->srp.rsp.tag;
+
+ /* If the linked bit is on and status is good */
+ if (test_bit(V_LINKED, &iue->flags) && (status == NO_SENSE))
+ status = 0x10;
+
+ memset(iu, 0, sizeof(struct srp_rsp));
+ iu->srp.rsp.opcode = SRP_RSP;
+ iu->srp.rsp.req_lim_delta = 1;
+ iu->srp.rsp.tag = tag;
+
+ if (test_bit(V_DIOVER, &iue->flags))
+ iu->srp.rsp.flags |= SRP_RSP_FLAG_DIOVER;
+
+ iu->srp.rsp.data_in_res_cnt = 0;
+ iu->srp.rsp.data_out_res_cnt = 0;
+
+ iu->srp.rsp.flags &= ~SRP_RSP_FLAG_RSPVALID;
+
+ iu->srp.rsp.resp_data_len = 0;
+ iu->srp.rsp.status = status;
+ if (status) {
+ uint8_t *sense = iu->srp.rsp.data;
+
+ if (sc) {
+ iu->srp.rsp.flags |= SRP_RSP_FLAG_SNSVALID;
+ iu->srp.rsp.sense_data_len = SCSI_SENSE_BUFFERSIZE;
+ memcpy(sense, sc->sense_buffer, SCSI_SENSE_BUFFERSIZE);
+ } else {
+ iu->srp.rsp.status = SAM_STAT_CHECK_CONDITION;
+ iu->srp.rsp.flags |= SRP_RSP_FLAG_SNSVALID;
+ iu->srp.rsp.sense_data_len = SRP_RSP_SENSE_DATA_LEN;
+
+ /* Valid bit and 'current errors' */
+ sense[0] = (0x1 << 7 | 0x70);
+ /* Sense key */
+ sense[2] = status;
+ /* Additional sense length */
+ sense[7] = 0xa; /* 10 bytes */
+ /* Additional sense code */
+ sense[12] = asc;
+ }
+ }
+
+ send_iu(iue, sizeof(iu->srp.rsp) + SRP_RSP_SENSE_DATA_LEN,
+ VIOSRP_SRP_FORMAT);
+
+ return 0;
+}
+
+static int send_adapter_info(struct iu_entry *iue,
+ dma_addr_t remote_buffer, u16 length)
+{
+ struct srp_target *target = iue->target;
+ struct ibmvscsis_adapter *adapter = target->ldata;
+ dma_addr_t data_token;
+ struct mad_adapter_info_data *info;
+ int err;
+
+ info = dma_alloc_coherent(&adapter->dma_dev->dev, sizeof(*info),
+ &data_token, GFP_KERNEL);
+ if (!info) {
+ printk(KERN_ERR "bad dma_alloc_coherent %p\n", target);
+ return 1;
+ }
+
+ /* Get remote info */
+ err = h_copy_rdma(sizeof(*info), adapter->riobn, remote_buffer,
+ adapter->liobn, data_token);
+ if (err == H_SUCCESS) {
+ printk(KERN_INFO "Client connect: %s (%d)\n",
+ info->partition_name, info->partition_number);
+ }
+
+ memset(info, 0, sizeof(*info));
+
+ strcpy(info->srp_version, "16.a");
+ strncpy(info->partition_name, partition_name,
+ sizeof(info->partition_name));
+ info->partition_number = partition_number;
+ info->mad_version = 1;
+ info->os_type = 2;
+ info->port_max_txu[0] = DEFAULT_MAX_SECTORS << 9;
+
+ /* Send our info to remote */
+ err = h_copy_rdma(sizeof(*info), adapter->liobn, data_token,
+ adapter->riobn, remote_buffer);
+
+ dma_free_coherent(&adapter->dma_dev->dev, sizeof(*info), info,
+ data_token);
+ if (err != H_SUCCESS) {
+ printk(KERN_INFO "Error sending adapter info %d\n", err);
+ return 1;
+ }
+
+ return 0;
+}
+
+static int process_mad_iu(struct iu_entry *iue)
+{
+ union viosrp_iu *iu = vio_iu(iue);
+ struct viosrp_adapter_info *info;
+ struct viosrp_host_config *conf;
+
+ switch (iu->mad.empty_iu.common.type) {
+ case VIOSRP_EMPTY_IU_TYPE:
+ printk(KERN_ERR "%s\n", "Unsupported EMPTY MAD IU");
+ break;
+ case VIOSRP_ERROR_LOG_TYPE:
+ printk(KERN_ERR "%s\n", "Unsupported ERROR LOG MAD IU");
+ iu->mad.error_log.common.status = 1;
+ send_iu(iue, sizeof(iu->mad.error_log), VIOSRP_MAD_FORMAT);
+ break;
+ case VIOSRP_ADAPTER_INFO_TYPE:
+ info = &iu->mad.adapter_info;
+ info->common.status = send_adapter_info(iue, info->buffer,
+ info->common.length);
+ send_iu(iue, sizeof(*info), VIOSRP_MAD_FORMAT);
+ break;
+ case VIOSRP_HOST_CONFIG_TYPE:
+ conf = &iu->mad.host_config;
+ conf->common.status = 1;
+ send_iu(iue, sizeof(*conf), VIOSRP_MAD_FORMAT);
+ break;
+ default:
+ printk(KERN_ERR "Unknown type %u\n", iu->srp.rsp.opcode);
+ iu->mad.empty_iu.common.status = VIOSRP_MAD_NOT_SUPPORTED;
+ send_iu(iue, sizeof(iu->mad), VIOSRP_MAD_FORMAT);
+ break;
+ }
+
+ return 1;
+}
+
+static void process_login(struct iu_entry *iue)
+{
+ union viosrp_iu *iu = vio_iu(iue);
+ struct srp_login_rsp *rsp = &iu->srp.login_rsp;
+ u64 tag = iu->srp.rsp.tag;
+
+ /*
+ * TODO handle case that requested size is wrong and buffer
+ * format is wrong
+ */
+ memset(iu, 0, sizeof(struct srp_login_rsp));
+ rsp->opcode = SRP_LOGIN_RSP;
+ rsp->req_lim_delta = INITIAL_SRP_LIMIT;
+ rsp->tag = tag;
+ rsp->max_it_iu_len = sizeof(union srp_iu);
+ rsp->max_ti_iu_len = sizeof(union srp_iu);
+ /* direct and indirect */
+ rsp->buf_fmt = SRP_BUF_FORMAT_DIRECT | SRP_BUF_FORMAT_INDIRECT;
+
+ send_iu(iue, sizeof(*rsp), VIOSRP_SRP_FORMAT);
+}
+
+static void process_tsk_mgmt(struct iu_entry *iue)
+{
+ union viosrp_iu *iu = vio_iu(iue);
+ uint64_t tag = iu->srp.rsp.tag;
+ uint8_t *resp_data = iu->srp.rsp.data;
+
+ memset(iu, 0, sizeof(struct srp_rsp));
+ iu->srp.rsp.opcode = SRP_RSP;
+ iu->srp.rsp.req_lim_delta = 1;
+ iu->srp.rsp.tag = tag;
+
+ iu->srp.rsp.data_in_res_cnt = 0;
+ iu->srp.rsp.data_out_res_cnt = 0;
+
+ iu->srp.rsp.flags &= ~SRP_RSP_FLAG_RSPVALID;
+
+ iu->srp.rsp.resp_data_len = 4;
+ /* TASK MANAGEMENT FUNCTION NOT SUPPORTED for now */
+ resp_data[3] = 4;
+
+ send_iu(iue, sizeof(iu->srp.rsp) + iu->srp.rsp.resp_data_len,
+ VIOSRP_SRP_FORMAT);
+}
+
+static int process_srp_iu(struct iu_entry *iue)
+{
+ union viosrp_iu *iu = vio_iu(iue);
+ struct srp_target *target = iue->target;
+ int done = 1;
+ u8 opcode = iu->srp.rsp.opcode;
+ unsigned long flags;
+
+ switch (opcode) {
+ case SRP_LOGIN_REQ:
+ process_login(iue);
+ break;
+ case SRP_TSK_MGMT:
+ process_tsk_mgmt(iue);
+ break;
+ case SRP_CMD:
+ spin_lock_irqsave(&target->lock, flags);
+ list_add_tail(&iue->ilist, &target->cmd_queue);
+ spin_unlock_irqrestore(&target->lock, flags);
+ done = 0;
+ break;
+ case SRP_LOGIN_RSP:
+ case SRP_I_LOGOUT:
+ case SRP_T_LOGOUT:
+ case SRP_RSP:
+ case SRP_CRED_REQ:
+ case SRP_CRED_RSP:
+ case SRP_AER_REQ:
+ case SRP_AER_RSP:
+ printk(KERN_ERR "Unsupported type %u\n", opcode);
+ break;
+ default:
+ printk(KERN_ERR "Unknown type %u\n", opcode);
+ }
+
+ return done;
+}
+
+static void process_iu(struct viosrp_crq *crq,
+ struct ibmvscsis_adapter *adapter)
+{
+ struct iu_entry *iue;
+ long err;
+ int done = 1;
+
+ iue = srp_iu_get(&adapter->srpt);
+ if (!iue) {
+ printk(KERN_ERR "Error getting IU from pool\n");
+ return;
+ }
+
+ iue->remote_token = crq->IU_data_ptr;
+
+ err = h_copy_rdma(crq->IU_length, adapter->riobn,
+ iue->remote_token, adapter->liobn, iue->sbuf->dma);
+
+ if (err != H_SUCCESS) {
+ printk(KERN_ERR "%ld transferring data error %p\n", err, iue);
+ goto out;
+ }
+
+ if (crq->format == VIOSRP_MAD_FORMAT)
+ done = process_mad_iu(iue);
+ else
+ done = process_srp_iu(iue);
+out:
+ if (done)
+ srp_iu_put(iue);
+}
+
+static void process_crq(struct viosrp_crq *crq,
+ struct ibmvscsis_adapter *adapter)
+{
+ switch (crq->valid) {
+ case 0xC0:
+ /* initialization */
+ switch (crq->format) {
+ case 0x01:
+ h_send_crq(adapter->dma_dev->unit_address,
+ 0xC002000000000000, 0);
+ break;
+ case 0x02:
+ break;
+ default:
+ printk(KERN_ERR "Unknown format %u\n", crq->format);
+ }
+ break;
+ case 0xFF:
+ /* transport event */
+ break;
+ case 0x80:
+ /* real payload */
+ switch (crq->format) {
+ case VIOSRP_SRP_FORMAT:
+ case VIOSRP_MAD_FORMAT:
+ process_iu(crq, adapter);
+ break;
+ case VIOSRP_OS400_FORMAT:
+ case VIOSRP_AIX_FORMAT:
+ case VIOSRP_LINUX_FORMAT:
+ case VIOSRP_INLINE_FORMAT:
+ printk(KERN_ERR "Unsupported format %u\n", crq->format);
+ break;
+ default:
+ printk(KERN_ERR "Unknown format %u\n", crq->format);
+ }
+ break;
+ default:
+ printk(KERN_ERR "unknown message type 0x%02x!?\n", crq->valid);
+ }
+}
+
+static inline struct viosrp_crq *next_crq(struct crq_queue *queue)
+{
+ struct viosrp_crq *crq;
+ unsigned long flags;
+
+ spin_lock_irqsave(&queue->lock, flags);
+ crq = &queue->msgs[queue->cur];
+ if (crq->valid & 0x80) {
+ if (++queue->cur == queue->size)
+ queue->cur = 0;
+ } else
+ crq = NULL;
+ spin_unlock_irqrestore(&queue->lock, flags);
+
+ return crq;
+}
+
+static int tcm_queuecommand(struct ibmvscsis_adapter *adapter,
+ struct ibmvscsis_cmnd *vsc,
+ struct srp_cmd *cmd)
+{
+ struct se_cmd *se_cmd;
+ int attr;
+ int data_len;
+ int ret;
+
+ switch (cmd->task_attr) {
+ case SRP_SIMPLE_TASK:
+ attr = MSG_SIMPLE_TAG;
+ break;
+ case SRP_ORDERED_TASK:
+ attr = MSG_ORDERED_TAG;
+ break;
+ case SRP_HEAD_TASK:
+ attr = MSG_HEAD_TAG;
+ break;
+ default:
+ printk(KERN_WARNING "Task attribute %d not supported\n",
+ cmd->task_attr);
+ attr = MSG_SIMPLE_TAG;
+ }
+
+ data_len = srp_data_length(cmd, srp_cmd_direction(cmd));
+
+ se_cmd = &vsc->se_cmd;
+
+ transport_init_se_cmd(se_cmd,
+ adapter->se_tpg.se_tpg_tfo,
+ adapter->se_sess, data_len,
+ srp_cmd_direction(cmd),
+ attr, vsc->sense_buf);
+
+ ret = transport_get_lun_for_cmd(se_cmd, NULL, cmd->lun);
+ if (ret) {
+ printk(KERN_ERR "invalid lun %u\n", GETLUN(cmd->lun));
+ transport_send_check_condition_and_sense(se_cmd,
+ se_cmd->scsi_sense_reason,
+ 0);
+ return ret;
+ }
+
+ transport_device_setup_cmd(se_cmd);
+ transport_generic_handle_cdb_map(se_cmd);
+
+ return 0;
+}
+
+static int ibmvscsis_new_cmd_map(struct se_cmd *se_cmd)
+{
+ struct ibmvscsis_cmnd *cmd =
+ container_of(se_cmd, struct ibmvscsis_cmnd, se_cmd);
+ struct scsi_cmnd *sc = &cmd->sc;
+ struct iu_entry *iue = (struct iu_entry *)sc->SCp.ptr;
+ struct srp_cmd *scmd = iue->sbuf->buf;
+ int ret;
+
+ /*
+ * Allocate the necessary tasks to complete the received CDB+data
+ */
+ ret = transport_generic_allocate_tasks(se_cmd, scmd->cdb);
+ if (ret == -1) {
+ /* Out of Resources */
+ return PYX_TRANSPORT_LU_COMM_FAILURE;
+ } else if (ret == -2) {
+ /*
+ * Handle case for SAM_STAT_RESERVATION_CONFLICT
+ */
+ if (se_cmd->se_cmd_flags & SCF_SCSI_RESERVATION_CONFLICT)
+ return PYX_TRANSPORT_RESERVATION_CONFLICT;
+ /*
+ * Otherwise, return SAM_STAT_CHECK_CONDITION and return
+ * sense data
+ */
+ return PYX_TRANSPORT_USE_SENSE_REASON;
+ }
+
+ return 0;
+}
+
+static void ibmvscsis_check_stop_free(struct se_cmd *se_cmd)
+{
+ if (se_cmd->se_tmr_req)
+ return;
+ transport_generic_free_cmd(se_cmd, 0, 1, 0);
+}
+
+static u64 scsi_lun_to_int(u64 lun)
+{
+ if (GETBUS(lun) || GETLUN(lun))
+ return ~0UL;
+ else
+ return GETTARGET(lun);
+}
+
+struct inquiry_data {
+ u8 qual_type;
+ u8 rmb_reserve;
+ u8 version;
+ u8 aerc_naca_hisup_format;
+ u8 addl_len;
+ u8 sccs_reserved;
+ u8 bque_encserv_vs_multip_mchngr_reserved;
+ u8 reladr_reserved_linked_cmdqueue_vs;
+ char vendor[8];
+ char product[16];
+ char revision[4];
+ char vendor_specific[20];
+ char reserved1[2];
+ char version_descriptor[16];
+ char reserved2[22];
+ char unique[158];
+};
+
+static u64 make_lun(unsigned int bus, unsigned int target, unsigned int lun)
+{
+ u16 result = (0x8000 |
+ ((target & 0x003f) << 8) |
+ ((bus & 0x0007) << 5) |
+ (lun & 0x001f));
+ return ((u64) result) << 48;
+}
+
+static int ibmvscsis_inquiry(struct ibmvscsis_adapter *adapter,
+ struct srp_cmd *cmd, char *data)
+{
+ struct se_portal_group *se_tpg = &adapter->se_tpg;
+ struct inquiry_data *id = (struct inquiry_data *)data;
+ u64 unpacked_lun, lun = cmd->lun;
+ u8 *cdb = cmd->cdb;
+ int len;
+
+ if (!data)
+ printk(KERN_INFO "%s %d: oomu\n", __func__, __LINE__);
+
+ if (((cdb[1] & 0x3) == 0x3) || (!(cdb[1] & 0x3) && cdb[2])) {
+ printk(KERN_INFO "%s %d: invalid req\n", __func__, __LINE__);
+ return 0;
+ }
+
+ if (cdb[1] & 0x3)
+ printk(KERN_INFO "%s %d: needs the normal path\n",
+ __func__, __LINE__);
+ else {
+ id->qual_type = TYPE_DISK;
+ id->rmb_reserve = 0x00;
+ id->version = 0x84; /* ISO/IE */
+ id->aerc_naca_hisup_format = 0x22; /* naca & fmt 0x02 */
+ id->addl_len = sizeof(*id) - 4;
+ id->bque_encserv_vs_multip_mchngr_reserved = 0x00;
+ id->reladr_reserved_linked_cmdqueue_vs = 0x02; /* CMDQ */
+ memcpy(id->vendor, "IBM ", 8);
+ /*
+ * Don't even ask about the next bit. AIX uses
+ * hardcoded device naming to recognize device types
+ * and their client won't work unless we use VOPTA and
+ * VDASD.
+ */
+ if (id->qual_type == TYPE_ROM)
+ memcpy(id->product, "VOPTA blkdev ", 16);
+ else
+ memcpy(id->product, "VDASD blkdev ", 16);
+
+ memcpy(id->revision, "0001", 4);
+
+ snprintf(id->unique, sizeof(id->unique),
+ "IBM-VSCSI-%s-P%d-%x-%d-%d-%d\n",
+ system_id,
+ partition_number,
+ adapter->dma_dev->unit_address,
+ GETBUS(lun),
+ GETTARGET(lun),
+ GETLUN(lun));
+ }
+
+ len = min_t(int, sizeof(*id), cdb[4]);
+
+ unpacked_lun = scsi_lun_to_int(cmd->lun);
+
+ spin_lock(&se_tpg->tpg_lun_lock);
+
+ if (unpacked_lun < TRANSPORT_MAX_LUNS_PER_TPG &&
+ se_tpg->tpg_lun_list[unpacked_lun].lun_status ==
+ TRANSPORT_LUN_STATUS_ACTIVE)
+ ;
+ else
+ data[0] = TYPE_NO_LUN;
+
+ spin_unlock(&se_tpg->tpg_lun_lock);
+
+ return len;
+}
+
+static int ibmvscsis_mode_sense(struct ibmvscsis_adapter *adapter,
+ struct srp_cmd *cmd, char *mode)
+{
+ int bytes;
+ struct se_portal_group *se_tpg = &adapter->se_tpg;
+ u64 unpacked_lun;
+ struct se_lun *lun;
+ u32 blocks;
+
+ unpacked_lun = scsi_lun_to_int(cmd->lun);
+
+ spin_lock(&se_tpg->tpg_lun_lock);
+
+ lun = &se_tpg->tpg_lun_list[unpacked_lun];
+
+ blocks = TRANSPORT(lun->lun_se_dev)->get_blocks(lun->lun_se_dev);
+
+ spin_unlock(&se_tpg->tpg_lun_lock);
+
+ switch (cmd->cdb[2]) {
+ case 0:
+ case 0x3f:
+ mode[1] = 0x00; /* Default medium */
+ /* if (iue->req.vd->b.ro) */
+ if (0)
+ mode[2] = 0x80; /* device specific */
+ else
+ mode[2] = 0x00; /* device specific */
+
+ /* note the DPOFUA bit is set to zero! */
+ mode[3] = 0x08; /* block descriptor length */
+ *((u32 *) &mode[4]) = blocks - 1;
+ *((u32 *) &mode[8]) = 512;
+ bytes = mode[0] = 12; /* length */
+ break;
+
+ case 0x08: /* Cache page */
+ mode[1] = 0x00; /* Default medium */
+ if (0)
+ mode[2] = 0x80; /* device specific */
+ else
+ mode[2] = 0x00; /* device specific */
+
+ /* note the DPOFUA bit is set to zero! */
+ mode[3] = 0x08; /* block descriptor length */
+ *((u32 *) &mode[4]) = blocks - 1;
+ *((u32 *) &mode[8]) = 512;
+
+ /* Cache page */
+ mode[12] = 0x08; /* page */
+ mode[13] = 0x12; /* page length */
+ mode[14] = 0x01; /* no cache (0x04 for read/write cache) */
+
+ bytes = mode[0] = 12 + mode[13]; /* length */
+ break;
+ }
+
+ return bytes;
+}
+
+static int ibmvscsis_report_luns(struct ibmvscsis_adapter *adapter,
+ struct srp_cmd *cmd, u64 *data)
+{
+ u64 lun;
+ struct se_portal_group *se_tpg = &adapter->se_tpg;
+ int i, idx;
+ int alen, oalen, nr_luns, rbuflen = 4096;
+
+ alen = get_unaligned_be32(&cmd->cdb[6]);
+
+ alen &= ~(8 - 1);
+ oalen = alen;
+
+ if (cmd->lun) {
+ nr_luns = 1;
+ goto done;
+ }
+
+ alen -= 8;
+ rbuflen -= 8; /* FIXME */
+ idx = 2;
+ nr_luns = 1;
+
+ spin_lock(&se_tpg->tpg_lun_lock);
+ for (i = 0; i < 255; i++) {
+ if (se_tpg->tpg_lun_list[i].lun_status !=
+ TRANSPORT_LUN_STATUS_ACTIVE)
+ continue;
+
+ lun = make_lun(0, i & 0x003f, 0);
+ data[idx++] = cpu_to_be64(lun);
+ alen -= 8;
+ if (!alen)
+ break;
+ rbuflen -= 8;
+ if (!rbuflen)
+ break;
+
+ nr_luns++;
+ }
+ spin_unlock(&se_tpg->tpg_lun_lock);
+done:
+ put_unaligned_be32(nr_luns * 8, data);
+ return min(oalen, nr_luns * 8 + 8);
+}
+
+static int ibmvscsis_rdma(struct scsi_cmnd *sc, struct scatterlist *sg, int nsg,
+ struct srp_direct_buf *md, int nmd,
+ enum dma_data_direction dir, unsigned int rest)
+{
+ struct iu_entry *iue = (struct iu_entry *) sc->SCp.ptr;
+ struct srp_target *target = iue->target;
+ struct ibmvscsis_adapter *adapter = target->ldata;
+ dma_addr_t token;
+ long err;
+ unsigned int done = 0;
+ int i, sidx, soff;
+
+ sidx = soff = 0;
+ token = sg_dma_address(sg + sidx);
+
+ for (i = 0; i < nmd && rest; i++) {
+ unsigned int mdone, mlen;
+
+ mlen = min(rest, md[i].len);
+ for (mdone = 0; mlen;) {
+ int slen = min(sg_dma_len(sg + sidx) - soff, mlen);
+
+ if (dir == DMA_TO_DEVICE)
+ err = h_copy_rdma(slen,
+ adapter->riobn,
+ md[i].va + mdone,
+ adapter->liobn,
+ token + soff);
+ else
+ err = h_copy_rdma(slen,
+ adapter->liobn,
+ token + soff,
+ adapter->riobn,
+ md[i].va + mdone);
+
+ if (err != H_SUCCESS) {
+ printk(KERN_ERR "rdma error %d %d %ld\n",
+ dir, slen, err);
+ return -EIO;
+ }
+
+ mlen -= slen;
+ mdone += slen;
+ soff += slen;
+ done += slen;
+
+ if (soff == sg_dma_len(sg + sidx)) {
+ sidx++;
+ soff = 0;
+ token = sg_dma_address(sg + sidx);
+
+ if (sidx > nsg) {
+ printk(KERN_ERR "out of sg %p %d %d\n",
+ iue, sidx, nsg);
+ return -EIO;
+ }
+ }
+ };
+
+ rest -= mlen;
+ }
+ return 0;
+}
+
+static int ibmvscsis_cmd_done(struct scsi_cmnd *sc)
+{
+ unsigned long flags;
+ struct iu_entry *iue = (struct iu_entry *) sc->SCp.ptr;
+ struct srp_target *target = iue->target;
+ int err = 0;
+
+ if (scsi_sg_count(sc))
+ err = srp_transfer_data(sc, &vio_iu(iue)->srp.cmd,
+ ibmvscsis_rdma, 1, 1);
+
+ spin_lock_irqsave(&target->lock, flags);
+ list_del(&iue->ilist);
+ spin_unlock_irqrestore(&target->lock, flags);
+
+ if (err || sc->result != SAM_STAT_GOOD) {
+ printk(KERN_ERR "operation failed %p %d %x\n",
+ iue, sc->result, vio_iu(iue)->srp.cmd.cdb[0]);
+ send_rsp(iue, sc, HARDWARE_ERROR, 0x00);
+ } else
+ send_rsp(iue, sc, NO_SENSE, 0x00);
+
+ /* done(sc); */
+ srp_iu_put(iue);
+ return 0;
+}
+
+struct ibmvscsis_cmd {
+ /* Used for libsrp processing callbacks */
+ struct scsi_cmnd sc;
+ /* Used for TCM Core operations */
+ struct se_cmd se_cmd;
+ /* Sense buffer that will be mapped into outgoing status */
+ unsigned char sense_buf[TRANSPORT_SENSE_BUFFER];
+};
+
+static int ibmvscsis_write_pending(struct se_cmd *se_cmd)
+{
+ struct ibmvscsis_cmnd *cmd = container_of(se_cmd,
+ struct ibmvscsis_cmnd, se_cmd);
+ struct scsi_cmnd *sc = &cmd->sc;
+ struct iu_entry *iue = (struct iu_entry *) sc->SCp.ptr;
+ int ret;
+
+ sc->sdb.length = se_cmd->data_length;
+
+ if ((se_cmd->se_cmd_flags & SCF_SCSI_DATA_SG_IO_CDB) ||
+ (se_cmd->se_cmd_flags & SCF_SCSI_CONTROL_SG_IO_CDB)) {
+ transport_do_task_sg_chain(se_cmd);
+
+ sc->sdb.table.nents = T_TASK(se_cmd)->t_tasks_sg_chained_no;
+ sc->sdb.table.sgl = T_TASK(se_cmd)->t_tasks_sg_chained;
+ } else if (se_cmd->se_cmd_flags & SCF_SCSI_CONTROL_NONSG_IO_CDB) {
+ /*
+ * Use T_TASK(se_cmd)->t_tasks_sg_bounce for control CDBs
+ * using a contigious buffer
+ */
+ sg_init_table(&T_TASK(se_cmd)->t_tasks_sg_bounce, 1);
+ sg_set_buf(&T_TASK(se_cmd)->t_tasks_sg_bounce,
+ T_TASK(se_cmd)->t_task_buf, se_cmd->data_length);
+
+ sc->sdb.table.nents = 1;
+ sc->sdb.table.sgl = &T_TASK(se_cmd)->t_tasks_sg_bounce;
+ }
+
+ ret = srp_transfer_data(sc, &vio_iu(iue)->srp.cmd,
+ ibmvscsis_rdma, 1, 1);
+ if (ret) {
+ printk(KERN_ERR "srp_transfer_data() failed: %d\n", ret);
+ return PYX_TRANSPORT_LU_COMM_FAILURE;
+ }
+ /*
+ * We now tell TCM to add this WRITE CDB directly into the TCM storage
+ * object execution queue.
+ */
+ transport_generic_process_write(se_cmd);
+ return 0;
+}
+
+static int ibmvscsis_queue_data_in(struct se_cmd *se_cmd)
+{
+ struct ibmvscsis_cmnd *cmd = container_of(se_cmd,
+ struct ibmvscsis_cmnd, se_cmd);
+ struct scsi_cmnd *sc = &cmd->sc;
+ /*
+ * Check for overflow residual count
+ */
+ if (se_cmd->se_cmd_flags & SCF_OVERFLOW_BIT)
+ scsi_set_resid(sc, se_cmd->residual_count);
+
+ sc->sdb.length = se_cmd->data_length;
+
+ /*
+ * Setup the struct se_task->task_sg[] chained SG list
+ */
+ if ((se_cmd->se_cmd_flags & SCF_SCSI_DATA_SG_IO_CDB) ||
+ (se_cmd->se_cmd_flags & SCF_SCSI_CONTROL_SG_IO_CDB)) {
+ transport_do_task_sg_chain(se_cmd);
+
+ sc->sdb.table.nents = T_TASK(se_cmd)->t_tasks_sg_chained_no;
+ sc->sdb.table.sgl = T_TASK(se_cmd)->t_tasks_sg_chained;
+ } else if (se_cmd->se_cmd_flags & SCF_SCSI_CONTROL_NONSG_IO_CDB) {
+ /*
+ * Use T_TASK(se_cmd)->t_tasks_sg_bounce for control CDBs
+ * using a contigious buffer
+ */
+ sg_init_table(&T_TASK(se_cmd)->t_tasks_sg_bounce, 1);
+ sg_set_buf(&T_TASK(se_cmd)->t_tasks_sg_bounce,
+ T_TASK(se_cmd)->t_task_buf, se_cmd->data_length);
+
+ sc->sdb.table.nents = 1;
+ sc->sdb.table.sgl = &T_TASK(se_cmd)->t_tasks_sg_bounce;
+ }
+ /*
+ * This will call srp_transfer_data() and post the response
+ * to VIO via libsrp.
+ */
+ ibmvscsis_cmd_done(sc);
+ return 0;
+}
+
+static int ibmvscsis_queue_status(struct se_cmd *se_cmd)
+{
+ struct ibmvscsis_cmnd *cmd = container_of(se_cmd,
+ struct ibmvscsis_cmnd, se_cmd);
+ struct scsi_cmnd *sc = &cmd->sc;
+ /*
+ * Copy any generated SENSE data into sc->sense_buffer and
+ * set the appropiate sc->result to be translated by
+ * ibmvscsis_cmd_done()
+ */
+ if (se_cmd->sense_buffer &&
+ ((se_cmd->se_cmd_flags & SCF_TRANSPORT_TASK_SENSE) ||
+ (se_cmd->se_cmd_flags & SCF_EMULATED_TASK_SENSE))) {
+ memcpy((void *)sc->sense_buffer, (void *)se_cmd->sense_buffer,
+ SCSI_SENSE_BUFFERSIZE);
+ sc->result = host_byte(DID_OK) | driver_byte(DRIVER_SENSE) |
+ SAM_STAT_CHECK_CONDITION;
+ } else
+ sc->result = host_byte(DID_OK) | se_cmd->scsi_status;
+ /*
+ * Finally post the response to VIO via libsrp.
+ */
+ ibmvscsis_cmd_done(sc);
+ return 0;
+}
+
+static int ibmvscsis_queuecommand(struct ibmvscsis_adapter *adapter,
+ struct iu_entry *iue)
+{
+ int data_len;
+ struct srp_cmd *cmd = iue->sbuf->buf;
+ struct scsi_cmnd *sc;
+ struct page *pg;
+ struct ibmvscsis_cmnd *vsc;
+
+ data_len = srp_data_length(cmd, srp_cmd_direction(cmd));
+
+ vsc = kzalloc(sizeof(*vsc), GFP_KERNEL);
+ sc = &vsc->sc;
+ sc->sense_buffer = vsc->sense_buf;
+ sc->cmnd = cmd->cdb;
+ sc->SCp.ptr = (char *)iue;
+
+ switch (cmd->cdb[0]) {
+ case INQUIRY:
+ sg_alloc_table(&sc->sdb.table, 1, GFP_KERNEL);
+ pg = alloc_page(GFP_KERNEL|__GFP_ZERO);
+ sc->sdb.length = ibmvscsis_inquiry(adapter, cmd,
+ page_address(pg));
+ sg_set_page(sc->sdb.table.sgl, pg, sc->sdb.length, 0);
+ ibmvscsis_cmd_done(sc);
+ sg_free_table(&sc->sdb.table);
+ __free_page(pg);
+ kfree(vsc);
+ break;
+ case REPORT_LUNS:
+ sg_alloc_table(&sc->sdb.table, 1, GFP_KERNEL);
+ pg = alloc_page(GFP_KERNEL|__GFP_ZERO);
+ sc->sdb.length = ibmvscsis_report_luns(adapter, cmd,
+ page_address(pg));
+ sg_set_page(sc->sdb.table.sgl, pg, sc->sdb.length, 0);
+ ibmvscsis_cmd_done(sc);
+ sg_free_table(&sc->sdb.table);
+ __free_page(pg);
+ kfree(vsc);
+ break;
+ case MODE_SENSE:
+ /* fixme: needs to use tcm */
+ sg_alloc_table(&sc->sdb.table, 1, GFP_KERNEL);
+ pg = alloc_page(GFP_KERNEL|__GFP_ZERO);
+ sc->sdb.length = ibmvscsis_mode_sense(adapter,
+ cmd, page_address(pg));
+ sg_set_page(sc->sdb.table.sgl, pg, sc->sdb.length, 0);
+ ibmvscsis_cmd_done(sc);
+ sg_free_table(&sc->sdb.table);
+ __free_page(pg);
+ kfree(vsc);
+ break;
+ default:
+ tcm_queuecommand(adapter, vsc, cmd);
+ break;
+ }
+
+ return 0;
+}
+
+static void handle_cmd_queue(struct ibmvscsis_adapter *adapter)
+{
+ struct srp_target *target = &adapter->srpt;
+ struct iu_entry *iue;
+ struct srp_cmd *cmd;
+ unsigned long flags;
+ int err;
+
+retry:
+ spin_lock_irqsave(&target->lock, flags);
+
+ list_for_each_entry(iue, &target->cmd_queue, ilist) {
+ if (!test_and_set_bit(V_FLYING, &iue->flags)) {
+ spin_unlock_irqrestore(&target->lock, flags);
+ err = ibmvscsis_queuecommand(adapter, iue);
+ if (err) {
+ printk(KERN_ERR "cannot queue cmd %p %d\n",
+ cmd, err);
+ srp_iu_put(iue);
+ }
+ goto retry;
+ }
+ }
+
+ spin_unlock_irqrestore(&target->lock, flags);
+}
+
+static void handle_crq(struct work_struct *work)
+{
+ struct ibmvscsis_adapter *adapter =
+ container_of(work, struct ibmvscsis_adapter, crq_work);
+ struct viosrp_crq *crq;
+ int done = 0;
+
+ while (!done) {
+ while ((crq = next_crq(&adapter->crq_queue)) != NULL) {
+ process_crq(crq, adapter);
+ crq->valid = 0x00;
+ }
+
+ vio_enable_interrupts(adapter->dma_dev);
+
+ crq = next_crq(&adapter->crq_queue);
+ if (crq) {
+ vio_disable_interrupts(adapter->dma_dev);
+ process_crq(crq, adapter);
+ crq->valid = 0x00;
+ } else
+ done = 1;
+ }
+
+ handle_cmd_queue(adapter);
+}
+
+static irqreturn_t ibmvscsis_interrupt(int dummy, void *data)
+{
+ struct ibmvscsis_adapter *adapter = data;
+
+ vio_disable_interrupts(adapter->dma_dev);
+ schedule_work(&adapter->crq_work);
+
+ return IRQ_HANDLED;
+}
+
+static int crq_queue_create(struct crq_queue *queue,
+ struct ibmvscsis_adapter *adapter)
+{
+ int err;
+ struct vio_dev *vdev = adapter->dma_dev;
+
+ queue->msgs = (struct viosrp_crq *)get_zeroed_page(GFP_KERNEL);
+ if (!queue->msgs)
+ goto malloc_failed;
+ queue->size = PAGE_SIZE / sizeof(*queue->msgs);
+
+ queue->msg_token = dma_map_single(&vdev->dev, queue->msgs,
+ queue->size * sizeof(*queue->msgs),
+ DMA_BIDIRECTIONAL);
+
+ if (dma_mapping_error(&vdev->dev, queue->msg_token))
+ goto map_failed;
+
+ err = h_reg_crq(vdev->unit_address, queue->msg_token,
+ PAGE_SIZE);
+
+ /* If the adapter was left active for some reason (like kexec)
+ * try freeing and re-registering
+ */
+ if (err == H_RESOURCE) {
+ do {
+ err = h_free_crq(vdev->unit_address);
+ } while (err == H_BUSY || H_IS_LONG_BUSY(err));
+
+ err = h_reg_crq(vdev->unit_address, queue->msg_token,
+ PAGE_SIZE);
+ }
+
+ if (err != H_SUCCESS && err != 2) {
+ printk(KERN_ERR "Error 0x%x opening virtual adapter\n", err);
+ goto reg_crq_failed;
+ }
+
+ err = request_irq(vdev->irq, &ibmvscsis_interrupt,
+ IRQF_DISABLED, "ibmvscsis", adapter);
+ if (err)
+ goto req_irq_failed;
+
+ vio_enable_interrupts(vdev);
+
+ h_send_crq(vdev->unit_address, 0xC001000000000000, 0);
+
+ queue->cur = 0;
+ spin_lock_init(&queue->lock);
+
+ return 0;
+
+req_irq_failed:
+ do {
+ err = h_free_crq(vdev->unit_address);
+ } while (err == H_BUSY || H_IS_LONG_BUSY(err));
+
+reg_crq_failed:
+ dma_unmap_single(&vdev->dev, queue->msg_token,
+ queue->size * sizeof(*queue->msgs), DMA_BIDIRECTIONAL);
+map_failed:
+ free_page((unsigned long) queue->msgs);
+
+malloc_failed:
+ return -ENOMEM;
+}
+
+static void crq_queue_destroy(struct ibmvscsis_adapter *adapter)
+{
+ struct crq_queue *queue = &adapter->crq_queue;
+ int err;
+
+ free_irq(adapter->dma_dev->irq, adapter);
+ flush_work_sync(&adapter->crq_work);
+ do {
+ err = h_free_crq(adapter->dma_dev->unit_address);
+ } while (err == H_BUSY || H_IS_LONG_BUSY(err));
+
+ dma_unmap_single(&adapter->dma_dev->dev, queue->msg_token,
+ queue->size * sizeof(*queue->msgs), DMA_BIDIRECTIONAL);
+
+ free_page((unsigned long)queue->msgs);
+}
+
+static int ibmvscsis_probe(struct vio_dev *dev, const struct vio_device_id *id)
+{
+ unsigned int *dma, dma_size;
+ unsigned long flags;
+ int ret;
+ struct ibmvscsis_adapter *adapter;
+
+ adapter = kzalloc(sizeof(*adapter), GFP_KERNEL);
+ if (!adapter)
+ return -ENOMEM;
+
+ adapter->dma_dev = dev;
+
+ dma = (unsigned int *)vio_get_attribute(dev, "ibm,my-dma-window",
+ &dma_size);
+ if (!dma || dma_size != 40) {
+ printk(KERN_ERR "Couldn't get window property %d\n", dma_size);
+ kfree(adapter);
+ return -EIO;
+ }
+
+ adapter->liobn = dma[0];
+ adapter->riobn = dma[5];
+ ret = strict_strtoul(dev_name(&dev->dev), 10, &adapter->tport_tpgt);
+
+ spin_lock_irqsave(&tpg_lock, flags);
+ list_add(&adapter->siblings, &tpg_list);
+ spin_unlock_irqrestore(&tpg_lock, flags);
+
+ INIT_WORK(&adapter->crq_work, handle_crq);
+
+ dev_set_drvdata(&dev->dev, adapter);
+
+ ret = srp_target_alloc(&adapter->srpt, &dev->dev, INITIAL_SRP_LIMIT,
+ SRP_MAX_IU_LEN);
+
+ adapter->srpt.ldata = adapter;
+
+ ret = crq_queue_create(&adapter->crq_queue, adapter);
+
+ return 0;
+}
+
+static int ibmvscsis_remove(struct vio_dev *dev)
+{
+ struct ibmvscsis_adapter *adapter = dev_get_drvdata(&dev->dev);
+ unsigned long flags;
+
+ spin_lock_irqsave(&tpg_lock, flags);
+ list_del(&adapter->siblings);
+ spin_unlock_irqrestore(&tpg_lock, flags);
+
+ crq_queue_destroy(adapter);
+
+ srp_target_free(&adapter->srpt);
+
+ kfree(adapter);
+ return 0;
+}
+
+static struct vio_device_id ibmvscsis_device_table[] __devinitdata = {
+ {"v-scsi-host", "IBM,v-scsi-host"},
+ {"", ""}
+};
+
+MODULE_DEVICE_TABLE(vio, ibmvscsis_device_table);
+
+static struct vio_driver ibmvscsis_driver = {
+ .id_table = ibmvscsis_device_table,
+ .probe = ibmvscsis_probe,
+ .remove = ibmvscsis_remove,
+ .driver = {
+ .name = "ibmvscsis",
+ .owner = THIS_MODULE,
+ }
+};
+
+static int get_system_info(void)
+{
+ struct device_node *rootdn;
+ const char *id, *model, *name;
+ const unsigned int *num;
+
+ rootdn = of_find_node_by_path("/");
+ if (!rootdn)
+ return -ENOENT;
+
+ model = of_get_property(rootdn, "model", NULL);
+ id = of_get_property(rootdn, "system-id", NULL);
+ if (model && id)
+ snprintf(system_id, sizeof(system_id), "%s-%s", model, id);
+
+ name = of_get_property(rootdn, "ibm,partition-name", NULL);
+ if (name)
+ strncpy(partition_name, name, sizeof(partition_name));
+
+ num = of_get_property(rootdn, "ibm,partition-no", NULL);
+ if (num)
+ partition_number = *num;
+
+ of_node_put(rootdn);
+ return 0;
+}
+
+static int ibmvscsis_register_configfs(void)
+{
+ struct target_fabric_configfs *fabric;
+ int ret;
+
+ printk(KERN_INFO "IBMVSCSIS fabric module %s on %s/%s"
+ " on "UTS_RELEASE"\n", IBMVSCSIS_VERSION, utsname()->sysname,
+ utsname()->machine);
+ /*
+ * Register the top level struct config_item_type with TCM core
+ */
+ fabric = target_fabric_configfs_init(THIS_MODULE, "ibmvscsis");
+ if (!(fabric)) {
+ printk(KERN_ERR "target_fabric_configfs_init() failed\n");
+ return -ENOMEM;
+ }
+ /*
+ * Setup fabric->tf_ops from our local ibmvscsis_ops
+ */
+ fabric->tf_ops = ibmvscsis_ops;
+ /*
+ * Setup default attribute lists for various fabric->tf_cit_tmpl
+ */
+ TF_CIT_TMPL(fabric)->tfc_wwn_cit.ct_attrs = ibmvscsis_wwn_attrs;
+ TF_CIT_TMPL(fabric)->tfc_tpg_base_cit.ct_attrs = NULL;
+ TF_CIT_TMPL(fabric)->tfc_tpg_attrib_cit.ct_attrs = NULL;
+ TF_CIT_TMPL(fabric)->tfc_tpg_param_cit.ct_attrs = NULL;
+ TF_CIT_TMPL(fabric)->tfc_tpg_np_base_cit.ct_attrs = NULL;
+ TF_CIT_TMPL(fabric)->tfc_tpg_nacl_base_cit.ct_attrs = NULL;
+ TF_CIT_TMPL(fabric)->tfc_tpg_nacl_attrib_cit.ct_attrs = NULL;
+ TF_CIT_TMPL(fabric)->tfc_tpg_nacl_auth_cit.ct_attrs = NULL;
+ TF_CIT_TMPL(fabric)->tfc_tpg_nacl_param_cit.ct_attrs = NULL;
+ /*
+ * Register the fabric for use within TCM
+ */
+ ret = target_fabric_configfs_register(fabric);
+ if (ret < 0) {
+ printk(KERN_ERR "target_fabric_configfs_register() failed"
+ " for IBMVSCSIS\n");
+ target_fabric_configfs_deregister(fabric);
+ return ret;
+ }
+ /*
+ * Setup our local pointer to *fabric
+ */
+ ibmvscsis_fabric_configfs = fabric;
+ printk(KERN_INFO "IBMVSCSIS[0] - Set fabric -> ibmvscsis_fabric_configfs\n");
+ return 0;
+};
+
+static void ibmvscsis_deregister_configfs(void)
+{
+ if (!(ibmvscsis_fabric_configfs))
+ return;
+
+ target_fabric_configfs_deregister(ibmvscsis_fabric_configfs);
+ ibmvscsis_fabric_configfs = NULL;
+ printk(KERN_INFO "IBMVSCSIS[0] - Cleared ibmvscsis_fabric_configfs\n");
+};
+
+static int __init ibmvscsis_init(void)
+{
+ int ret;
+
+ ret = get_system_info();
+ if (ret)
+ return ret;
+
+ ret = vio_register_driver(&ibmvscsis_driver);
+ if (ret)
+ return ret;
+
+ ret = ibmvscsis_register_configfs();
+ if (ret < 0)
+ return ret;
+
+ return 0;
+};
+
+static void ibmvscsis_exit(void)
+{
+ vio_unregister_driver(&ibmvscsis_driver);
+ ibmvscsis_deregister_configfs();
+};
+
+MODULE_DESCRIPTION("IBMVSCSIS series fabric driver");
+MODULE_AUTHOR("FUJITA Tomonori");
+MODULE_LICENSE("GPL");
+module_init(ibmvscsis_init);
+module_exit(ibmvscsis_exit);
--
1.7.2.3
^ permalink raw reply related
* Re: [RFC] Inter-processor Mailboxes Drivers
From: Hiroshi DOYU @ 2011-02-14 7:32 UTC (permalink / raw)
To: linus.walleij
Cc: meador_inge, Hollis_Blanchard, sunder.svit, openmcapi-dev,
linuxppc-dev, linux-arm-kernel
In-Reply-To: <AANLkTikoExk30pqdcHXCA2K_oJB=VJ5_AnCkoYUrEt3X@mail.gmail.com>
From: ext Linus Walleij <linus.walleij@linaro.org>
Subject: Re: [RFC] Inter-processor Mailboxes Drivers
Date: Sun, 13 Feb 2011 22:16:12 +0100
> 2011/2/12 Sundar <sunder.svit@gmail.com>:
> =
>> At least I would like this; I wanted to generalize such mailbox IPCs=
>> right from the day when I was working on one, but coudnt really
>> work on that.
>>
>>> =A0 =A02. Does something like this already exist?
>>
>> Not generic as you say; but apart from the OMAP platforms,
>> you could refer to arch/arm/mach-ux500/prcmu for a mailbox based
>> IPC on the U8500 platform.
> =
> We also have this thing:
> arch/arm/mach-ux500/mbox-db5500.c
> =
> It's another mailbox driver, this one talks to the modem in the
> U5500 (basically a physical transport for the CAIF protocol).
> (For the U8500 I think modem IPC is instead handled with
> a high-speed hardware FIFO, a bit different.)
> =
>>> =A0 =A03. Is someone else already working on this?
>>
>> Not sure of that too :), but I am CCing Linus W, the maintainer
>> of U8500 if he thinks it is a good idea to come up with a mailbox IP=
C
>> framework
> =
> I don't know too much about the subject actually, I've not been
> deeply into any such code. I don't think anyone is working
> on something general from ST-Ericsson or Linaro.
> =
> Recently I saw that Texas Instruments are posting a "hardware
> spinlock" framework though, this would be on a related tone,
> but I think it's for shared data structures (control path) rather
> than buffer passing (data path). I'm guessing this works like
> that one CPU gets to spin waiting for another one to release
> the lock.
> =
> Given that we may have a framework for hardware spinlock
> and that we don't want to stockpile drivers into arch/*
> or drivers/misc/* I would say it's intuitively a good idea,
> but the question is what data types you would pass in?
> In arch/arm/mach-ux500/include/mach/mbox-db5500.h
> we have a struct like this:
> =
> /**
> * struct mbox - Mailbox instance struct
> * @list: Linked list head.
> * @pdev: Pointer to device struct.
> * @cb: Callback function. Will be called
> * when new data is received.
> * @client_data: Clients private data. Will be sent back
> * in the callback function.
> * @virtbase_peer: Virtual address for outgoing mailbox.
> * @virtbase_local: Virtual address for incoming mailbox.
> * @buffer: Then internal queue for outgoing messages.
> * @name: Name of this mailbox.
> * @buffer_available: Completion variable to achieve "blocking send=
".
> * This variable will be signaled when there is
> * internal buffer space available.
> * @client_blocked: To keep track if any client is currently
> * blocked.
> * @lock: Spinlock to protect this mailbox instance.
> * @write_index: Index in internal buffer to write to.
> * @read_index: Index in internal buffer to read from.
> * @allocated: Indicates whether this particular mailbox
> * id has been allocated by someone.
> */
> struct mbox {
> struct list_head list;
> struct platform_device *pdev;
> mbox_recv_cb_t *cb;
> void *client_data;
> void __iomem *virtbase_peer;
> void __iomem *virtbase_local;
> u32 buffer[MBOX_BUF_SIZE];
> char name[MBOX_NAME_SIZE];
> struct completion buffer_available;
> u8 client_blocked;
> spinlock_t lock;
> u8 write_index;
> u8 read_index;
> bool allocated;
> };
> =
> Compare OMAPs mailboxes in
> arch/arm/plat-omap/include/plat/mailbox.h:
> =
> typedef u32 mbox_msg_t;
> =
> truct omap_mbox_ops {
> omap_mbox_type_t type;
> int (*startup)(struct omap_mbox *mbox);
> void (*shutdown)(struct omap_mbox *mbox);
> /* fifo */
> mbox_msg_t (*fifo_read)(struct omap_mbox *mbox);
> void (*fifo_write)(struct omap_mbox *mbox, mbox_ms=
g_t msg);
> int (*fifo_empty)(struct omap_mbox *mbox);
> int (*fifo_full)(struct omap_mbox *mbox);
> /* irq */
> void (*enable_irq)(struct omap_mbox *mbox,
> omap_mbox_irq_t irq);=
> void (*disable_irq)(struct omap_mbox *mbox,
> omap_mbox_irq_t irq);=
> void (*ack_irq)(struct omap_mbox *mbox, omap_mbox_=
irq_t irq);
> int (*is_irq)(struct omap_mbox *mbox, omap_mbox_i=
rq_t irq);
> /* ctx */
> void (*save_ctx)(struct omap_mbox *mbox);
> void (*restore_ctx)(struct omap_mbox *mbox);
> };
> =
> struct omap_mbox_queue {
> spinlock_t lock;
> struct kfifo fifo;
> struct work_struct work;
> struct tasklet_struct tasklet;
> struct omap_mbox *mbox;
> bool full;
> };
> =
> struct omap_mbox {
> char *name;
> unsigned int irq;
> struct omap_mbox_queue *txq, *rxq;
> struct omap_mbox_ops *ops;
> struct device *dev;
> void *priv;
> int use_count;
> struct blocking_notifier_head notifier;
> };
> =
> Some of this may be generalized? I dunno, they look quite
> different but maybe queueing etc can actually be made general
> enough to form a framework.
OMAP mailbox is the interrupt driven 32bit unit H/W FIFO to other
cores.
"struct omap_mbox_ops" was provided mainly to absorb the difference
between OMAP1 and OMAP2+ from H/W POV. So generally the layer could
be:
-----------------------
character device driver
-----------------------
generic mailbox driver
-----------------------
H/W registration
-----------------------
In OMAP case, in addition to the above, it could be exceptionally:
-----------------------
character device driver
-----------------------
generic mailbox driver
-----------------------
H/W registration
-----------------------
OMAP 1 | OMAP2+
-----------------------
So "character device driver"(interface) and "generic mailbox
driver"(queuing) may be able to abstructed/generalized.
^ permalink raw reply
* Re: [RFC] Inter-processor Mailboxes Drivers
From: Linus Walleij @ 2011-02-14 8:39 UTC (permalink / raw)
To: Hiroshi DOYU
Cc: meador_inge, Hollis_Blanchard, sunder.svit, openmcapi-dev,
linuxppc-dev, linux-arm-kernel
In-Reply-To: <20110214.093257.58795266617213863.Hiroshi.DOYU@nokia.com>
On Mon, Feb 14, 2011 at 8:32 AM, Hiroshi DOYU <Hiroshi.DOYU@nokia.com> wrote:
> OMAP mailbox is the interrupt driven 32bit unit H/W FIFO to other
> cores.
How is it used? Is it a low-traffic (like single 32bit words etc) signal
control-path link while the actual high-throughput data-path is done
with shared memory? (That is how the db5500 mbox works anyways.)
Linus Walleij
^ permalink raw reply
* Re: [RFC] Inter-processor Mailboxes Drivers
From: Hiroshi DOYU @ 2011-02-14 7:21 UTC (permalink / raw)
To: meador_inge
Cc: openmcapi-dev, Hollis_Blanchard, linuxppc-dev, linux-arm-kernel
In-Reply-To: <4D55A7F7.5090700@mentor.com>
Hi Meador,
From: ext Meador Inge <meador_inge@mentor.com>
Subject: [RFC] Inter-processor Mailboxes Drivers
Date: Fri, 11 Feb 2011 15:19:51 -0600
> Hi All,
>
> I am currently working on building AMP systems using OpenMCAPI
> (https://bitbucket.org/hollisb/openmcapi/wiki/Home) as the
> inter-processor communication mechanism. With OpenMCAPI we, of
> course,
> need a way to send messages to various cores. On some Freescale PPC
> platforms (e.g. P1022DS, MPC8572DS), we have been using message
> registers to do this work. Recently, I was looking at the OMAP4
> mailboxes to gear up for moving into ARM based platforms.
>
> With that, I noticed 'arch/arm/plat-omap/mailbox.c'. This is very
> specific to the OMAP4 boards. I am looking at designing a new set of
> drivers to expose a mailbox service to userspace that will be used
> for inter-processor communication. This would entail the traditional
> generic/specific driver split:
>
> 1. Hardware specific bits somewhere under '.../arch/*'. Drivers
> for the MPIC message registers on Power and OMAP4 mailboxes, for
> example.
> 2. A higher level driver under '.../drivers/mailbox/*'. That the
> pieces in (1) would register with. This piece would expose the
> main kernel API.
> 3. Userspace interfaces for accessing the mailboxes. A
> '/dev/mailbox1', '/dev/mailbox2', etc... mapping, for example.
>
> Now I have the following questions:
>
> 1. Do others see value in this?
Yes.
I discussed this with TI(Hari) long time ago, but it didn't proceed
with some reason, not techinical one.
> 2. Does something like this already exist?
> 3. Is someone else already working on this?
>
> Any feedback will be greatly appreciated.
Now the basic concpet can be devided into 3 parts, (1)HW dependent,
(2) generic driver, (3) character device interface. I guess that it
might be good to have one _pseudo_ H/W instance, then easier for
verification without real H/W and firmwares, across multiplatforms.
^ permalink raw reply
* RE: [PATCH V8 03/10] USB/ppc4xx: Add Synopsys DWC OTG Core InterfaceLayer
From: David Laight @ 2011-02-14 8:53 UTC (permalink / raw)
To: Tirumala Marri, Greg KH, Alexander Gordeev
Cc: linuxppc-dev, linux-usb, Mark Miesfeld, Fushen Chen
In-Reply-To: <4f99d54a42d4f13663c88b0b081f047b@mail.gmail.com>
=20
> > Sorry, I don't understand that. I think u32 is always 32bit=20
> > 4byte on all archs. Right?
>=20
> Yes.
>=20
> Use an unsigned long if you want to hold a pointer correctly on all
> arches.
Although that is true for many systems (and probably all ppc Linux)
it isn't necessarily true (eg 64 bit Microsoft Windows).
C99 inttypes.h should define uintptr_t as an unsigned integer
type that is large enough to hold a (data) pointer.
I'm not sure if this is defined for the Linux kernel.
David
^ permalink raw reply
* Re: [RFC] Inter-processor Mailboxes Drivers
From: Hiroshi DOYU @ 2011-02-14 8:55 UTC (permalink / raw)
To: linus.walleij
Cc: meador_inge, Hollis_Blanchard, sunder.svit, openmcapi-dev,
linuxppc-dev, linux-arm-kernel
In-Reply-To: <AANLkTimnHHhYKnvUgsMo_jsKaYdY+XuABZ+FV0p25JLi@mail.gmail.com>
From: ext Linus Walleij <linus.walleij@linaro.org>
Subject: Re: [RFC] Inter-processor Mailboxes Drivers
Date: Mon, 14 Feb 2011 09:39:32 +0100
> On Mon, Feb 14, 2011 at 8:32 AM, Hiroshi DOYU <Hiroshi.DOYU@nokia.com> wrote:
>
>> OMAP mailbox is the interrupt driven 32bit unit H/W FIFO to other
>> cores.
>
> How is it used? Is it a low-traffic (like single 32bit words etc) signal
> control-path link while the actual high-throughput data-path is done
> with shared memory? (That is how the db5500 mbox works anyways.)
Yes, maybe quite similar.
maibox is not single 32 bit but is 32 bit x 4(or 8?) slots fifo, IIRC,
and mainly it is used as notification between cores. And big amount of
data is transftered with sahred memory, which has been mapped onto the
virtual address space of the other side of core, in advance.
For example, typical usage of DSP, mp3 decoding,
1, ARM maps 2 shared memory area(input/output) onto DSP virtual
address space.
2, ARM fills mp3 data in input buffer.
3, ARM notifies DSP that data is ready in input buffer.
4, DSP decodes input data and put output data on output buffer.
5, DSP notifies that output buffer is ready.
Roughly something like the above. DSP S/W is multi-tasking, though.
Does db5500 use IOMMU for mapping shared memories?
^ permalink raw reply
* Re: [RFC] Inter-processor Mailboxes Drivers
From: Linus Walleij @ 2011-02-14 9:00 UTC (permalink / raw)
To: Hiroshi DOYU
Cc: meador_inge, Hollis_Blanchard, sunder.svit, openmcapi-dev,
linuxppc-dev, linux-arm-kernel
In-Reply-To: <20110214.105553.296482686007701595.Hiroshi.DOYU@nokia.com>
On Mon, Feb 14, 2011 at 9:55 AM, Hiroshi DOYU <Hiroshi.DOYU@nokia.com> wrote:
> Does db5500 use IOMMU for mapping shared memories?
Nope, it's a fixed physical allocation from the modem side
of the world.
Yours,
Linus Walleij
^ permalink raw reply
* Re: [RFC] Inter-processor Mailboxes Drivers
From: Hiroshi DOYU @ 2011-02-14 9:06 UTC (permalink / raw)
To: meador_inge, linus.walleij
Cc: openmcapi-dev, sunder.svit, Hollis_Blanchard, linuxppc-dev,
linux-arm-kernel
In-Reply-To: <20110214.105553.296482686007701595.Hiroshi.DOYU@nokia.com>
From: Hiroshi DOYU <Hiroshi.DOYU@nokia.com>
Subject: Re: [RFC] Inter-processor Mailboxes Drivers
Date: Mon, 14 Feb 2011 10:55:53 +0200 (EET)
> From: ext Linus Walleij <linus.walleij@linaro.org>
> Subject: Re: [RFC] Inter-processor Mailboxes Drivers
> Date: Mon, 14 Feb 2011 09:39:32 +0100
>
>> On Mon, Feb 14, 2011 at 8:32 AM, Hiroshi DOYU <Hiroshi.DOYU@nokia.com> wrote:
>>
>>> OMAP mailbox is the interrupt driven 32bit unit H/W FIFO to other
>>> cores.
>>
>> How is it used? Is it a low-traffic (like single 32bit words etc) signal
>> control-path link while the actual high-throughput data-path is done
>> with shared memory? (That is how the db5500 mbox works anyways.)
>
> Yes, maybe quite similar.
>
> maibox is not single 32 bit but is 32 bit x 4(or 8?) slots fifo, IIRC,
> and mainly it is used as notification between cores. And big amount of
> data is transftered with sahred memory, which has been mapped onto the
> virtual address space of the other side of core, in advance.
>
> For example, typical usage of DSP, mp3 decoding,
>
> 1, ARM maps 2 shared memory area(input/output) onto DSP virtual
> address space.
> 2, ARM fills mp3 data in input buffer.
> 3, ARM notifies DSP that data is ready in input buffer.
> 4, DSP decodes input data and put output data on output buffer.
> 5, DSP notifies that output buffer is ready.
>
> Roughly something like the above. DSP S/W is multi-tasking, though.
Here, ARM side process talks to DSP site process in their own way, and
also there are another cores, talking with their own protocols. So I
think that at least, protocol part should be pluggable anyway although
it doesn't have to be always in userland.
^ permalink raw reply
* Re: [PATCH v2 3/3] tcm ibmvscsis driver
From: Nicholas A. Bellinger @ 2011-02-14 9:12 UTC (permalink / raw)
To: FUJITA Tomonori; +Cc: brking, linuxppc-dev, linux-scsi
In-Reply-To: <20110214124821T.fujita.tomonori@lab.ntt.co.jp>
On Mon, 2011-02-14 at 12:48 +0900, FUJITA Tomonori wrote:
> This is the second version of tcm ibmvscsis driver. You can find the
> first version at:
>
> http://marc.info/?t=129734085600004&r=1&w=2
>
> The changes are:
>
> - send VIOSRP_MAD_NOT_SUPPORTED for unknown mad type requests.
> - fix inquiry typo
> - sends task management response (for now, 'NOT SUPPORTED').
> - remove dead code.
>
Your rev2 patch has been merged into lio-core-2.6.git/tcm_ibmvscsis
currently @ .38-rc4.
Thanks!
--nab
^ permalink raw reply
* Re: [RFC] Inter-processor Mailboxes Drivers
From: Jamie Iles @ 2011-02-14 10:01 UTC (permalink / raw)
To: Meador Inge
Cc: openmcapi-dev, Blanchard, Hollis, Hiroshi DOYU, linuxppc-dev,
linux-arm-kernel
In-Reply-To: <4D55A7F7.5090700@mentor.com>
On Fri, Feb 11, 2011 at 03:19:51PM -0600, Meador Inge wrote:
> 1. Hardware specific bits somewhere under '.../arch/*'. Drivers
> for the MPIC message registers on Power and OMAP4 mailboxes, for
> example.
> 2. A higher level driver under '.../drivers/mailbox/*'. That the
> pieces in (1) would register with. This piece would expose the
> main kernel API.
> 3. Userspace interfaces for accessing the mailboxes. A
> '/dev/mailbox1', '/dev/mailbox2', etc... mapping, for example.
How about using virtio for all of this and having the mailbox as a
notification/message passing driver for the virtio backend? There are
already virtio console and network drivers that could be useful for the
userspace part of it. drivers/virtio/virtio_ring.c might be a good
starting point if you thought there was some mileage in this approach.
Jamie
^ permalink raw reply
* Re: [RFC] Inter-processor Mailboxes Drivers
From: Ohad Ben-Cohen @ 2011-02-14 10:03 UTC (permalink / raw)
To: Jamie Iles
Cc: Meador Inge, Hiroshi DOYU, Blanchard, Hollis, openmcapi-dev,
linuxppc-dev, linux-arm-kernel
In-Reply-To: <20110214100104.GC4371@pulham.picochip.com>
On Mon, Feb 14, 2011 at 12:01 PM, Jamie Iles <jamie@jamieiles.com> wrote:
> On Fri, Feb 11, 2011 at 03:19:51PM -0600, Meador Inge wrote:
>> =A0 =A0 1. Hardware specific bits somewhere under '.../arch/*'. =A0Drive=
rs
>> =A0 =A0 =A0 =A0for the MPIC message registers on Power and OMAP4 mailbox=
es, for
>> =A0 =A0 =A0 =A0example.
>> =A0 =A0 2. A higher level driver under '.../drivers/mailbox/*'. =A0That =
the
>> =A0 =A0 =A0 =A0pieces in (1) would register with. =A0This piece would ex=
pose the
>> =A0 =A0 =A0 =A0main kernel API.
>> =A0 =A0 3. Userspace interfaces for accessing the mailboxes. =A0A
>> =A0 =A0 =A0 =A0'/dev/mailbox1', '/dev/mailbox2', etc... mapping, for exa=
mple.
>
> How about using virtio for all of this and having the mailbox as a
> notification/message passing driver for the virtio backend?
This is exactly what we are doing now, and it looks promising. expect
patches soon.
^ permalink raw reply
* [PATCH v3 3/3] tcm ibmvscsis driver
From: FUJITA Tomonori @ 2011-02-14 10:25 UTC (permalink / raw)
To: linux-scsi; +Cc: brking, linuxppc-dev, nab
This is the third version of tcm ibmvscsis driver. You can find the
first version at:
http://marc.info/?t=129734085600004&r=1&w=2
The changes are:
v3:
- fix task attribute (convert MSG_* to TASK_ATTR_*)
v2:
- send VIOSRP_MAD_NOT_SUPPORTED for unknown mad type requests.
- fix inquiry typo
- sends task management response (for now, 'NOT SUPPORTED').
- remove dead code.
=
From: FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp>
Subject: [PATCH v3 3/3] tcm ibmvscsis driver
This replaces ibmvstgt driver that uses the old target framework.
Signed-off-by: FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp>
---
drivers/scsi/ibmvscsi/Makefile | 4 +-
drivers/scsi/ibmvscsi/ibmvscsis.c | 1761 +++++++++++++++++++++++++++++++++++++
2 files changed, 1764 insertions(+), 1 deletions(-)
create mode 100644 drivers/scsi/ibmvscsi/ibmvscsis.c
diff --git a/drivers/scsi/ibmvscsi/Makefile b/drivers/scsi/ibmvscsi/Makefile
index a423d96..a615ea5 100644
--- a/drivers/scsi/ibmvscsi/Makefile
+++ b/drivers/scsi/ibmvscsi/Makefile
@@ -1,8 +1,10 @@
+EXTRA_CFLAGS += -I$(srctree)/drivers/target/
+
obj-$(CONFIG_SCSI_IBMVSCSI) += ibmvscsic.o
ibmvscsic-y += ibmvscsi.o
ibmvscsic-$(CONFIG_PPC_ISERIES) += iseries_vscsi.o
ibmvscsic-$(CONFIG_PPC_PSERIES) += rpa_vscsi.o
-obj-$(CONFIG_SCSI_IBMVSCSIS) += ibmvstgt.o
+obj-$(CONFIG_SCSI_IBMVSCSIS) += ibmvscsis.o
obj-$(CONFIG_SCSI_IBMVFC) += ibmvfc.o
diff --git a/drivers/scsi/ibmvscsi/ibmvscsis.c b/drivers/scsi/ibmvscsi/ibmvscsis.c
new file mode 100644
index 0000000..189c3a3
--- /dev/null
+++ b/drivers/scsi/ibmvscsi/ibmvscsis.c
@@ -0,0 +1,1761 @@
+/*
+ * IBM eServer i/pSeries Virtual SCSI Target Driver
+ * Copyright (C) 2003-2005 Dave Boutcher (boutcher@us.ibm.com) IBM Corp.
+ * Santiago Leon (santil@us.ibm.com) IBM Corp.
+ * Linda Xie (lxie@us.ibm.com) IBM Corp.
+ *
+ * Copyright (C) 2005-2011 FUJITA Tomonori <tomof@acm.org>
+ * Copyright (C) 2010 Nicholas A. Bellinger <nab@kernel.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.
+ *
+ * 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/slab.h>
+#include <linux/kthread.h>
+#include <linux/types.h>
+#include <linux/list.h>
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/ctype.h>
+#include <linux/utsname.h>
+#include <asm/unaligned.h>
+#include <scsi/scsi.h>
+#include <scsi/scsi_host.h>
+#include <scsi/scsi_device.h>
+#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_tcq.h>
+#include <scsi/libsrp.h>
+#include <scsi/libsas.h> /* For TASK_ATTR_* */
+#include <generated/utsrelease.h>
+
+#include <target/target_core_base.h>
+#include <target/target_core_transport.h>
+#include <target/target_core_fabric_ops.h>
+#include <target/target_core_fabric_lib.h>
+#include <target/target_core_fabric_configfs.h>
+#include <target/target_core_device.h>
+#include <target/target_core_tpg.h>
+#include <target/target_core_configfs.h>
+
+#include <asm/hvcall.h>
+#include <asm/iommu.h>
+#include <asm/prom.h>
+#include <asm/vio.h>
+
+#include "ibmvscsi.h"
+#include "viosrp.h"
+
+#define IBMVSCSIS_VERSION "v0.1"
+#define IBMVSCSIS_NAMELEN 32
+
+#define INITIAL_SRP_LIMIT 16
+#define DEFAULT_MAX_SECTORS 256
+
+/*
+ * Hypervisor calls.
+ */
+#define h_copy_rdma(l, sa, sb, da, db) \
+ plpar_hcall_norets(H_COPY_RDMA, l, sa, sb, da, db)
+#define h_send_crq(ua, l, h) \
+ plpar_hcall_norets(H_SEND_CRQ, ua, l, h)
+#define h_reg_crq(ua, tok, sz)\
+ plpar_hcall_norets(H_REG_CRQ, ua, tok, sz);
+#define h_free_crq(ua) \
+ plpar_hcall_norets(H_FREE_CRQ, ua);
+
+#define GETTARGET(x) ((int)((((u64)(x)) >> 56) & 0x003f))
+#define GETBUS(x) ((int)((((u64)(x)) >> 53) & 0x0007))
+#define GETLUN(x) ((int)((((u64)(x)) >> 48) & 0x001f))
+
+/*
+ * These are fixed for the system and come from the Open Firmware device tree.
+ * We just store them here to save getting them every time.
+ */
+static char system_id[64] = "";
+static char partition_name[97] = "UNKNOWN";
+static unsigned int partition_number = -1;
+
+static LIST_HEAD(tpg_list);
+static DEFINE_SPINLOCK(tpg_lock);
+
+struct ibmvscsis_adapter {
+ struct vio_dev *dma_dev;
+ struct list_head siblings;
+
+ struct crq_queue crq_queue;
+
+ struct work_struct crq_work;
+
+ unsigned long liobn;
+ unsigned long riobn;
+
+ /* todo: remove */
+ struct srp_target srpt;
+
+ /* SRP port target portal group tag for TCM */
+ unsigned long tport_tpgt;
+
+ /* Returned by ibmvscsis_make_tpg() */
+ struct se_portal_group se_tpg;
+
+ struct se_session *se_sess;
+
+
+ /* SCSI protocol the tport is providing */
+ u8 tport_proto_id;
+ /* Binary World Wide unique Port Name for SRP Target port */
+ u64 tport_wwpn;
+ /* ASCII formatted WWPN for SRP Target port */
+ char tport_name[IBMVSCSIS_NAMELEN];
+ /* Returned by ibmvscsis_make_tport() */
+ struct se_wwn tport_wwn;
+};
+
+struct ibmvscsis_cmnd {
+ /* Used for libsrp processing callbacks */
+ struct scsi_cmnd sc;
+ /* Used for TCM Core operations */
+ struct se_cmd se_cmd;
+ /* Sense buffer that will be mapped into outgoing status */
+ unsigned char sense_buf[TRANSPORT_SENSE_BUFFER];
+};
+
+static int ibmvscsis_check_true(struct se_portal_group *se_tpg)
+{
+ return 1;
+}
+
+static int ibmvscsis_check_false(struct se_portal_group *se_tpg)
+{
+ return 0;
+}
+
+static char *ibmvscsis_get_fabric_name(void)
+{
+ return "ibmvscsis";
+}
+
+static u8 ibmvscsis_get_fabric_proto_ident(struct se_portal_group *se_tpg)
+{
+ return 4;
+}
+
+static char *ibmvscsis_get_fabric_wwn(struct se_portal_group *se_tpg)
+{
+ struct ibmvscsis_adapter *adapter =
+ container_of(se_tpg, struct ibmvscsis_adapter, se_tpg);
+
+ return adapter->tport_name;
+}
+
+static u16 ibmvscsis_get_tag(struct se_portal_group *se_tpg)
+{
+ struct ibmvscsis_adapter *adapter =
+ container_of(se_tpg, struct ibmvscsis_adapter, se_tpg);
+ return adapter->tport_tpgt;
+}
+
+static u32 ibmvscsis_get_default_depth(struct se_portal_group *se_tpg)
+{
+ return 1;
+}
+
+/* we don't care about the transport id since we never use pr. */
+static u32 ibmvscsis_get_pr_transport_id(struct se_portal_group *se_tpg,
+ struct se_node_acl *se_nacl,
+ struct t10_pr_registration *pr_reg,
+ int *format_code,
+ unsigned char *buf)
+{
+ return 24;
+}
+
+static u32 ibmvscsis_get_pr_transport_id_len(struct se_portal_group *se_tpg,
+ struct se_node_acl *se_nacl,
+ struct t10_pr_registration *pr_reg,
+ int *format_code)
+{
+ return 24;
+}
+
+static char *ibmvscsis_parse_pr_out_transport_id(struct se_portal_group *se_tpg,
+ const char *buf,
+ u32 *out_tid_len,
+ char **port_nexus_ptr)
+{
+ return NULL;
+}
+
+struct ibmvscsis_nacl {
+ /* Binary World Wide unique Port Name for SRP Initiator port */
+ u64 iport_wwpn;
+ /* ASCII formatted WWPN for Sas Initiator port */
+ char iport_name[IBMVSCSIS_NAMELEN];
+ /* Returned by ibmvscsis_make_nodeacl() */
+ struct se_node_acl se_node_acl;
+};
+
+static struct se_node_acl *ibmvscsis_alloc_fabric_acl(struct se_portal_group *se_tpg)
+{
+ struct ibmvscsis_nacl *nacl;
+
+ nacl = kzalloc(sizeof(struct ibmvscsis_nacl), GFP_KERNEL);
+ if (!(nacl)) {
+ printk(KERN_ERR "Unable to alocate struct ibmvscsis_nacl\n");
+ return NULL;
+ }
+
+ return &nacl->se_node_acl;
+}
+
+static void ibmvscsis_release_fabric_acl(struct se_portal_group *se_tpg,
+ struct se_node_acl *se_nacl)
+{
+ struct ibmvscsis_nacl *nacl = container_of(se_nacl,
+ struct ibmvscsis_nacl, se_node_acl);
+ kfree(nacl);
+}
+
+static u32 ibmvscsis_tpg_get_inst_index(struct se_portal_group *se_tpg)
+{
+ return 1;
+}
+
+static void ibmvscsis_release_cmd(struct se_cmd *se_cmd)
+{
+ struct ibmvscsis_cmnd *cmd =
+ container_of(se_cmd, struct ibmvscsis_cmnd, se_cmd);
+ kfree(cmd);
+ return;
+}
+
+static int ibmvscsis_shutdown_session(struct se_session *se_sess)
+{
+ return 0;
+}
+
+static void ibmvscsis_close_session(struct se_session *se_sess)
+{
+ return;
+}
+
+static void ibmvscsis_stop_session(struct se_session *se_sess,
+ int sess_sleep , int conn_sleep)
+{
+ return;
+}
+
+static void ibmvscsis_reset_nexus(struct se_session *se_sess)
+{
+ return;
+}
+
+static int ibmvscsis_sess_logged_in(struct se_session *se_sess)
+{
+ return 0;
+}
+
+static u32 ibmvscsis_sess_get_index(struct se_session *se_sess)
+{
+ return 0;
+}
+
+static int ibmvscsis_write_pending_status(struct se_cmd *se_cmd)
+{
+ return 0;
+}
+
+static void ibmvscsis_set_default_node_attrs(struct se_node_acl *nacl)
+{
+ return;
+}
+
+static u32 ibmvscsis_get_task_tag(struct se_cmd *se_cmd)
+{
+ return 0;
+}
+
+static int ibmvscsis_get_cmd_state(struct se_cmd *se_cmd)
+{
+ return 0;
+}
+
+static void ibmvscsis_new_cmd_failure(struct se_cmd *se_cmd)
+{
+ return;
+}
+
+static int ibmvscsis_queue_tm_rsp(struct se_cmd *se_cmd)
+{
+ return 0;
+}
+
+static u16 ibmvscsis_set_fabric_sense_len(struct se_cmd *se_cmd,
+ u32 sense_length)
+{
+ return 0;
+}
+
+static u16 ibmvscsis_get_fabric_sense_len(void)
+{
+ return 0;
+}
+
+static int ibmvscsis_is_state_remove(struct se_cmd *se_cmd)
+{
+ return 0;
+}
+
+static u64 make_lun(unsigned int bus, unsigned int target, unsigned int lun);
+
+static u64 ibmvscsis_pack_lun(unsigned int lun)
+{
+ return make_lun(0, lun & 0x003f, 0);
+}
+
+/* Local pointer to allocated TCM configfs fabric module */
+static struct target_fabric_configfs *ibmvscsis_fabric_configfs;
+
+static struct se_portal_group *ibmvscsis_make_tpg(struct se_wwn *wwn,
+ struct config_group *group,
+ const char *name)
+{
+ struct ibmvscsis_adapter *adapter =
+ container_of(wwn, struct ibmvscsis_adapter, tport_wwn);
+ struct se_node_acl *acl;
+ int ret;
+ char *dname = (char *)dev_name(&adapter->dma_dev->dev);
+
+ if (strncmp(name, "tpgt_1", 6))
+ return ERR_PTR(-EINVAL);
+
+ ret = core_tpg_register(&ibmvscsis_fabric_configfs->tf_ops, wwn,
+ &adapter->se_tpg, (void *)adapter,
+ TRANSPORT_TPG_TYPE_NORMAL);
+ if (ret)
+ return ERR_PTR(-ENOMEM);
+
+ adapter->se_sess = transport_init_session();
+ if (!adapter->se_sess) {
+ core_tpg_deregister(&adapter->se_tpg);
+ return ERR_PTR(-ENOMEM);
+ }
+
+ acl = core_tpg_check_initiator_node_acl(&adapter->se_tpg, dname);
+ if (!acl) {
+ transport_free_session(adapter->se_sess);
+ adapter->se_sess = NULL;
+ return ERR_PTR(-ENOMEM);
+ }
+ adapter->se_sess->se_node_acl = acl;
+
+ transport_register_session(&adapter->se_tpg,
+ adapter->se_sess->se_node_acl,
+ adapter->se_sess, adapter);
+
+ return &adapter->se_tpg;
+}
+
+static void ibmvscsis_drop_tpg(struct se_portal_group *se_tpg)
+{
+ struct ibmvscsis_adapter *adapter =
+ container_of(se_tpg, struct ibmvscsis_adapter, se_tpg);
+ unsigned long flags;
+
+
+ transport_deregister_session_configfs(adapter->se_sess);
+ transport_free_session(adapter->se_sess);
+ core_tpg_deregister(se_tpg);
+
+ spin_lock_irqsave(&tpg_lock, flags);
+ adapter->se_sess = NULL;
+ spin_unlock_irqrestore(&tpg_lock, flags);
+}
+
+static struct se_wwn *ibmvscsis_make_tport(struct target_fabric_configfs *tf,
+ struct config_group *group,
+ const char *name)
+{
+ struct ibmvscsis_adapter *adapter;
+ unsigned long tpgt, flags;
+
+ if (strict_strtoul(name, 10, &tpgt))
+ return NULL;
+
+ spin_lock_irqsave(&tpg_lock, flags);
+ list_for_each_entry(adapter, &tpg_list, siblings) {
+ if (tpgt == adapter->tport_tpgt)
+ goto found;
+ }
+
+ spin_unlock_irqrestore(&tpg_lock, flags);
+ return NULL;
+found:
+ spin_unlock_irqrestore(&tpg_lock, flags);
+
+ return &adapter->tport_wwn;
+}
+
+static void ibmvscsis_drop_tport(struct se_wwn *wwn)
+{
+}
+
+static ssize_t ibmvscsis_wwn_show_attr_version(struct target_fabric_configfs *tf,
+ char *page)
+{
+ return sprintf(page, "IBMVSCSIS fabric module %s on %s/%s"
+ "on "UTS_RELEASE"\n", IBMVSCSIS_VERSION, utsname()->sysname,
+ utsname()->machine);
+}
+
+TF_WWN_ATTR_RO(ibmvscsis, version);
+
+static struct configfs_attribute *ibmvscsis_wwn_attrs[] = {
+ &ibmvscsis_wwn_version.attr,
+ NULL,
+};
+
+static int ibmvscsis_write_pending(struct se_cmd *se_cmd);
+static int ibmvscsis_queue_data_in(struct se_cmd *se_cmd);
+static int ibmvscsis_queue_status(struct se_cmd *se_cmd);
+static int ibmvscsis_new_cmd_map(struct se_cmd *se_cmd);
+static void ibmvscsis_check_stop_free(struct se_cmd *se_cmd);
+
+static struct target_core_fabric_ops ibmvscsis_ops = {
+ .task_sg_chaining = 1,
+ .get_fabric_name = ibmvscsis_get_fabric_name,
+ .get_fabric_proto_ident = ibmvscsis_get_fabric_proto_ident,
+ .tpg_get_wwn = ibmvscsis_get_fabric_wwn,
+ .tpg_get_tag = ibmvscsis_get_tag,
+ .tpg_get_default_depth = ibmvscsis_get_default_depth,
+ .tpg_get_pr_transport_id = ibmvscsis_get_pr_transport_id,
+ .tpg_get_pr_transport_id_len = ibmvscsis_get_pr_transport_id_len,
+ .tpg_parse_pr_out_transport_id = ibmvscsis_parse_pr_out_transport_id,
+ .tpg_check_demo_mode = ibmvscsis_check_true,
+ .tpg_check_demo_mode_cache = ibmvscsis_check_true,
+ .tpg_check_demo_mode_write_protect = ibmvscsis_check_false,
+ .tpg_check_prod_mode_write_protect = ibmvscsis_check_false,
+ .tpg_alloc_fabric_acl = ibmvscsis_alloc_fabric_acl,
+ .tpg_release_fabric_acl = ibmvscsis_release_fabric_acl,
+ .tpg_get_inst_index = ibmvscsis_tpg_get_inst_index,
+ .new_cmd_map = ibmvscsis_new_cmd_map,
+ .check_stop_free = ibmvscsis_check_stop_free,
+ .release_cmd_to_pool = ibmvscsis_release_cmd,
+ .release_cmd_direct = ibmvscsis_release_cmd,
+ .shutdown_session = ibmvscsis_shutdown_session,
+ .close_session = ibmvscsis_close_session,
+ .stop_session = ibmvscsis_stop_session,
+ .fall_back_to_erl0 = ibmvscsis_reset_nexus,
+ .sess_logged_in = ibmvscsis_sess_logged_in,
+ .sess_get_index = ibmvscsis_sess_get_index,
+ .sess_get_initiator_sid = NULL,
+ .write_pending = ibmvscsis_write_pending,
+ .write_pending_status = ibmvscsis_write_pending_status,
+ .set_default_node_attributes = ibmvscsis_set_default_node_attrs,
+ .get_task_tag = ibmvscsis_get_task_tag,
+ .get_cmd_state = ibmvscsis_get_cmd_state,
+ .new_cmd_failure = ibmvscsis_new_cmd_failure,
+ .queue_data_in = ibmvscsis_queue_data_in,
+ .queue_status = ibmvscsis_queue_status,
+ .queue_tm_rsp = ibmvscsis_queue_tm_rsp,
+ .get_fabric_sense_len = ibmvscsis_get_fabric_sense_len,
+ .set_fabric_sense_len = ibmvscsis_set_fabric_sense_len,
+ .is_state_remove = ibmvscsis_is_state_remove,
+ .pack_lun = ibmvscsis_pack_lun,
+ .fabric_make_wwn = ibmvscsis_make_tport,
+ .fabric_drop_wwn = ibmvscsis_drop_tport,
+ .fabric_make_tpg = ibmvscsis_make_tpg,
+ .fabric_drop_tpg = ibmvscsis_drop_tpg,
+ .fabric_post_link = NULL,
+ .fabric_pre_unlink = NULL,
+ .fabric_make_np = NULL,
+ .fabric_drop_np = NULL,
+ .fabric_make_nodeacl = NULL,
+ .fabric_drop_nodeacl = NULL,
+};
+
+static inline union viosrp_iu *vio_iu(struct iu_entry *iue)
+{
+ return (union viosrp_iu *)(iue->sbuf->buf);
+}
+
+static int send_iu(struct iu_entry *iue, u64 length, u8 format)
+{
+ struct srp_target *target = iue->target;
+ struct ibmvscsis_adapter *adapter = target->ldata;
+ long rc, rc1;
+ union {
+ struct viosrp_crq cooked;
+ u64 raw[2];
+ } crq;
+
+ /* First copy the SRP */
+ rc = h_copy_rdma(length, adapter->liobn, iue->sbuf->dma,
+ adapter->riobn, iue->remote_token);
+
+ if (rc)
+ printk(KERN_ERR "Error %ld transferring data\n", rc);
+
+ crq.cooked.valid = 0x80;
+ crq.cooked.format = format;
+ crq.cooked.reserved = 0x00;
+ crq.cooked.timeout = 0x00;
+ crq.cooked.IU_length = length;
+ crq.cooked.IU_data_ptr = vio_iu(iue)->srp.rsp.tag;
+
+ if (rc == 0)
+ crq.cooked.status = 0x99; /* Just needs to be non-zero */
+ else
+ crq.cooked.status = 0x00;
+
+ rc1 = h_send_crq(adapter->dma_dev->unit_address, crq.raw[0],
+ crq.raw[1]);
+ if (rc1) {
+ printk(KERN_ERR "%ld sending response\n", rc1);
+ return rc1;
+ }
+
+ return rc;
+}
+
+#define SRP_RSP_SENSE_DATA_LEN 18
+
+static int send_rsp(struct iu_entry *iue, struct scsi_cmnd *sc,
+ unsigned char status, unsigned char asc)
+{
+ union viosrp_iu *iu = vio_iu(iue);
+ uint64_t tag = iu->srp.rsp.tag;
+
+ /* If the linked bit is on and status is good */
+ if (test_bit(V_LINKED, &iue->flags) && (status == NO_SENSE))
+ status = 0x10;
+
+ memset(iu, 0, sizeof(struct srp_rsp));
+ iu->srp.rsp.opcode = SRP_RSP;
+ iu->srp.rsp.req_lim_delta = 1;
+ iu->srp.rsp.tag = tag;
+
+ if (test_bit(V_DIOVER, &iue->flags))
+ iu->srp.rsp.flags |= SRP_RSP_FLAG_DIOVER;
+
+ iu->srp.rsp.data_in_res_cnt = 0;
+ iu->srp.rsp.data_out_res_cnt = 0;
+
+ iu->srp.rsp.flags &= ~SRP_RSP_FLAG_RSPVALID;
+
+ iu->srp.rsp.resp_data_len = 0;
+ iu->srp.rsp.status = status;
+ if (status) {
+ uint8_t *sense = iu->srp.rsp.data;
+
+ if (sc) {
+ iu->srp.rsp.flags |= SRP_RSP_FLAG_SNSVALID;
+ iu->srp.rsp.sense_data_len = SCSI_SENSE_BUFFERSIZE;
+ memcpy(sense, sc->sense_buffer, SCSI_SENSE_BUFFERSIZE);
+ } else {
+ iu->srp.rsp.status = SAM_STAT_CHECK_CONDITION;
+ iu->srp.rsp.flags |= SRP_RSP_FLAG_SNSVALID;
+ iu->srp.rsp.sense_data_len = SRP_RSP_SENSE_DATA_LEN;
+
+ /* Valid bit and 'current errors' */
+ sense[0] = (0x1 << 7 | 0x70);
+ /* Sense key */
+ sense[2] = status;
+ /* Additional sense length */
+ sense[7] = 0xa; /* 10 bytes */
+ /* Additional sense code */
+ sense[12] = asc;
+ }
+ }
+
+ send_iu(iue, sizeof(iu->srp.rsp) + SRP_RSP_SENSE_DATA_LEN,
+ VIOSRP_SRP_FORMAT);
+
+ return 0;
+}
+
+static int send_adapter_info(struct iu_entry *iue,
+ dma_addr_t remote_buffer, u16 length)
+{
+ struct srp_target *target = iue->target;
+ struct ibmvscsis_adapter *adapter = target->ldata;
+ dma_addr_t data_token;
+ struct mad_adapter_info_data *info;
+ int err;
+
+ info = dma_alloc_coherent(&adapter->dma_dev->dev, sizeof(*info),
+ &data_token, GFP_KERNEL);
+ if (!info) {
+ printk(KERN_ERR "bad dma_alloc_coherent %p\n", target);
+ return 1;
+ }
+
+ /* Get remote info */
+ err = h_copy_rdma(sizeof(*info), adapter->riobn, remote_buffer,
+ adapter->liobn, data_token);
+ if (err == H_SUCCESS) {
+ printk(KERN_INFO "Client connect: %s (%d)\n",
+ info->partition_name, info->partition_number);
+ }
+
+ memset(info, 0, sizeof(*info));
+
+ strcpy(info->srp_version, "16.a");
+ strncpy(info->partition_name, partition_name,
+ sizeof(info->partition_name));
+ info->partition_number = partition_number;
+ info->mad_version = 1;
+ info->os_type = 2;
+ info->port_max_txu[0] = DEFAULT_MAX_SECTORS << 9;
+
+ /* Send our info to remote */
+ err = h_copy_rdma(sizeof(*info), adapter->liobn, data_token,
+ adapter->riobn, remote_buffer);
+
+ dma_free_coherent(&adapter->dma_dev->dev, sizeof(*info), info,
+ data_token);
+ if (err != H_SUCCESS) {
+ printk(KERN_INFO "Error sending adapter info %d\n", err);
+ return 1;
+ }
+
+ return 0;
+}
+
+static int process_mad_iu(struct iu_entry *iue)
+{
+ union viosrp_iu *iu = vio_iu(iue);
+ struct viosrp_adapter_info *info;
+ struct viosrp_host_config *conf;
+
+ switch (iu->mad.empty_iu.common.type) {
+ case VIOSRP_EMPTY_IU_TYPE:
+ printk(KERN_ERR "%s\n", "Unsupported EMPTY MAD IU");
+ break;
+ case VIOSRP_ERROR_LOG_TYPE:
+ printk(KERN_ERR "%s\n", "Unsupported ERROR LOG MAD IU");
+ iu->mad.error_log.common.status = 1;
+ send_iu(iue, sizeof(iu->mad.error_log), VIOSRP_MAD_FORMAT);
+ break;
+ case VIOSRP_ADAPTER_INFO_TYPE:
+ info = &iu->mad.adapter_info;
+ info->common.status = send_adapter_info(iue, info->buffer,
+ info->common.length);
+ send_iu(iue, sizeof(*info), VIOSRP_MAD_FORMAT);
+ break;
+ case VIOSRP_HOST_CONFIG_TYPE:
+ conf = &iu->mad.host_config;
+ conf->common.status = 1;
+ send_iu(iue, sizeof(*conf), VIOSRP_MAD_FORMAT);
+ break;
+ default:
+ printk(KERN_ERR "Unknown type %u\n", iu->srp.rsp.opcode);
+ iu->mad.empty_iu.common.status = VIOSRP_MAD_NOT_SUPPORTED;
+ send_iu(iue, sizeof(iu->mad), VIOSRP_MAD_FORMAT);
+ break;
+ }
+
+ return 1;
+}
+
+static void process_login(struct iu_entry *iue)
+{
+ union viosrp_iu *iu = vio_iu(iue);
+ struct srp_login_rsp *rsp = &iu->srp.login_rsp;
+ u64 tag = iu->srp.rsp.tag;
+
+ /*
+ * TODO handle case that requested size is wrong and buffer
+ * format is wrong
+ */
+ memset(iu, 0, sizeof(struct srp_login_rsp));
+ rsp->opcode = SRP_LOGIN_RSP;
+ rsp->req_lim_delta = INITIAL_SRP_LIMIT;
+ rsp->tag = tag;
+ rsp->max_it_iu_len = sizeof(union srp_iu);
+ rsp->max_ti_iu_len = sizeof(union srp_iu);
+ /* direct and indirect */
+ rsp->buf_fmt = SRP_BUF_FORMAT_DIRECT | SRP_BUF_FORMAT_INDIRECT;
+
+ send_iu(iue, sizeof(*rsp), VIOSRP_SRP_FORMAT);
+}
+
+static void process_tsk_mgmt(struct iu_entry *iue)
+{
+ union viosrp_iu *iu = vio_iu(iue);
+ uint64_t tag = iu->srp.rsp.tag;
+ uint8_t *resp_data = iu->srp.rsp.data;
+
+ memset(iu, 0, sizeof(struct srp_rsp));
+ iu->srp.rsp.opcode = SRP_RSP;
+ iu->srp.rsp.req_lim_delta = 1;
+ iu->srp.rsp.tag = tag;
+
+ iu->srp.rsp.data_in_res_cnt = 0;
+ iu->srp.rsp.data_out_res_cnt = 0;
+
+ iu->srp.rsp.flags &= ~SRP_RSP_FLAG_RSPVALID;
+
+ iu->srp.rsp.resp_data_len = 4;
+ /* TASK MANAGEMENT FUNCTION NOT SUPPORTED for now */
+ resp_data[3] = 4;
+
+ send_iu(iue, sizeof(iu->srp.rsp) + iu->srp.rsp.resp_data_len,
+ VIOSRP_SRP_FORMAT);
+}
+
+static int process_srp_iu(struct iu_entry *iue)
+{
+ union viosrp_iu *iu = vio_iu(iue);
+ struct srp_target *target = iue->target;
+ int done = 1;
+ u8 opcode = iu->srp.rsp.opcode;
+ unsigned long flags;
+
+ switch (opcode) {
+ case SRP_LOGIN_REQ:
+ process_login(iue);
+ break;
+ case SRP_TSK_MGMT:
+ process_tsk_mgmt(iue);
+ break;
+ case SRP_CMD:
+ spin_lock_irqsave(&target->lock, flags);
+ list_add_tail(&iue->ilist, &target->cmd_queue);
+ spin_unlock_irqrestore(&target->lock, flags);
+ done = 0;
+ break;
+ case SRP_LOGIN_RSP:
+ case SRP_I_LOGOUT:
+ case SRP_T_LOGOUT:
+ case SRP_RSP:
+ case SRP_CRED_REQ:
+ case SRP_CRED_RSP:
+ case SRP_AER_REQ:
+ case SRP_AER_RSP:
+ printk(KERN_ERR "Unsupported type %u\n", opcode);
+ break;
+ default:
+ printk(KERN_ERR "Unknown type %u\n", opcode);
+ }
+
+ return done;
+}
+
+static void process_iu(struct viosrp_crq *crq,
+ struct ibmvscsis_adapter *adapter)
+{
+ struct iu_entry *iue;
+ long err;
+ int done = 1;
+
+ iue = srp_iu_get(&adapter->srpt);
+ if (!iue) {
+ printk(KERN_ERR "Error getting IU from pool\n");
+ return;
+ }
+
+ iue->remote_token = crq->IU_data_ptr;
+
+ err = h_copy_rdma(crq->IU_length, adapter->riobn,
+ iue->remote_token, adapter->liobn, iue->sbuf->dma);
+
+ if (err != H_SUCCESS) {
+ printk(KERN_ERR "%ld transferring data error %p\n", err, iue);
+ goto out;
+ }
+
+ if (crq->format == VIOSRP_MAD_FORMAT)
+ done = process_mad_iu(iue);
+ else
+ done = process_srp_iu(iue);
+out:
+ if (done)
+ srp_iu_put(iue);
+}
+
+static void process_crq(struct viosrp_crq *crq,
+ struct ibmvscsis_adapter *adapter)
+{
+ switch (crq->valid) {
+ case 0xC0:
+ /* initialization */
+ switch (crq->format) {
+ case 0x01:
+ h_send_crq(adapter->dma_dev->unit_address,
+ 0xC002000000000000, 0);
+ break;
+ case 0x02:
+ break;
+ default:
+ printk(KERN_ERR "Unknown format %u\n", crq->format);
+ }
+ break;
+ case 0xFF:
+ /* transport event */
+ break;
+ case 0x80:
+ /* real payload */
+ switch (crq->format) {
+ case VIOSRP_SRP_FORMAT:
+ case VIOSRP_MAD_FORMAT:
+ process_iu(crq, adapter);
+ break;
+ case VIOSRP_OS400_FORMAT:
+ case VIOSRP_AIX_FORMAT:
+ case VIOSRP_LINUX_FORMAT:
+ case VIOSRP_INLINE_FORMAT:
+ printk(KERN_ERR "Unsupported format %u\n", crq->format);
+ break;
+ default:
+ printk(KERN_ERR "Unknown format %u\n", crq->format);
+ }
+ break;
+ default:
+ printk(KERN_ERR "unknown message type 0x%02x!?\n", crq->valid);
+ }
+}
+
+static inline struct viosrp_crq *next_crq(struct crq_queue *queue)
+{
+ struct viosrp_crq *crq;
+ unsigned long flags;
+
+ spin_lock_irqsave(&queue->lock, flags);
+ crq = &queue->msgs[queue->cur];
+ if (crq->valid & 0x80) {
+ if (++queue->cur == queue->size)
+ queue->cur = 0;
+ } else
+ crq = NULL;
+ spin_unlock_irqrestore(&queue->lock, flags);
+
+ return crq;
+}
+
+static int tcm_queuecommand(struct ibmvscsis_adapter *adapter,
+ struct ibmvscsis_cmnd *vsc,
+ struct srp_cmd *cmd)
+{
+ struct se_cmd *se_cmd;
+ int attr;
+ int data_len;
+ int ret;
+
+ switch (cmd->task_attr) {
+ case SRP_SIMPLE_TASK:
+ attr = TASK_ATTR_SIMPLE;
+ break;
+ case SRP_ORDERED_TASK:
+ attr = TASK_ATTR_ORDERED;
+ break;
+ case SRP_HEAD_TASK:
+ attr = TASK_ATTR_HOQ;
+ break;
+ default:
+ printk(KERN_WARNING "Task attribute %d not supported\n",
+ cmd->task_attr);
+ attr = TASK_ATTR_SIMPLE;
+ }
+
+ data_len = srp_data_length(cmd, srp_cmd_direction(cmd));
+
+ se_cmd = &vsc->se_cmd;
+
+ transport_init_se_cmd(se_cmd,
+ adapter->se_tpg.se_tpg_tfo,
+ adapter->se_sess, data_len,
+ srp_cmd_direction(cmd),
+ attr, vsc->sense_buf);
+
+ ret = transport_get_lun_for_cmd(se_cmd, NULL, cmd->lun);
+ if (ret) {
+ printk(KERN_ERR "invalid lun %u\n", GETLUN(cmd->lun));
+ transport_send_check_condition_and_sense(se_cmd,
+ se_cmd->scsi_sense_reason,
+ 0);
+ return ret;
+ }
+
+ transport_device_setup_cmd(se_cmd);
+ transport_generic_handle_cdb_map(se_cmd);
+
+ return 0;
+}
+
+static int ibmvscsis_new_cmd_map(struct se_cmd *se_cmd)
+{
+ struct ibmvscsis_cmnd *cmd =
+ container_of(se_cmd, struct ibmvscsis_cmnd, se_cmd);
+ struct scsi_cmnd *sc = &cmd->sc;
+ struct iu_entry *iue = (struct iu_entry *)sc->SCp.ptr;
+ struct srp_cmd *scmd = iue->sbuf->buf;
+ int ret;
+
+ /*
+ * Allocate the necessary tasks to complete the received CDB+data
+ */
+ ret = transport_generic_allocate_tasks(se_cmd, scmd->cdb);
+ if (ret == -1) {
+ /* Out of Resources */
+ return PYX_TRANSPORT_LU_COMM_FAILURE;
+ } else if (ret == -2) {
+ /*
+ * Handle case for SAM_STAT_RESERVATION_CONFLICT
+ */
+ if (se_cmd->se_cmd_flags & SCF_SCSI_RESERVATION_CONFLICT)
+ return PYX_TRANSPORT_RESERVATION_CONFLICT;
+ /*
+ * Otherwise, return SAM_STAT_CHECK_CONDITION and return
+ * sense data
+ */
+ return PYX_TRANSPORT_USE_SENSE_REASON;
+ }
+
+ return 0;
+}
+
+static void ibmvscsis_check_stop_free(struct se_cmd *se_cmd)
+{
+ if (se_cmd->se_tmr_req)
+ return;
+ transport_generic_free_cmd(se_cmd, 0, 1, 0);
+}
+
+static u64 scsi_lun_to_int(u64 lun)
+{
+ if (GETBUS(lun) || GETLUN(lun))
+ return ~0UL;
+ else
+ return GETTARGET(lun);
+}
+
+struct inquiry_data {
+ u8 qual_type;
+ u8 rmb_reserve;
+ u8 version;
+ u8 aerc_naca_hisup_format;
+ u8 addl_len;
+ u8 sccs_reserved;
+ u8 bque_encserv_vs_multip_mchngr_reserved;
+ u8 reladr_reserved_linked_cmdqueue_vs;
+ char vendor[8];
+ char product[16];
+ char revision[4];
+ char vendor_specific[20];
+ char reserved1[2];
+ char version_descriptor[16];
+ char reserved2[22];
+ char unique[158];
+};
+
+static u64 make_lun(unsigned int bus, unsigned int target, unsigned int lun)
+{
+ u16 result = (0x8000 |
+ ((target & 0x003f) << 8) |
+ ((bus & 0x0007) << 5) |
+ (lun & 0x001f));
+ return ((u64) result) << 48;
+}
+
+static int ibmvscsis_inquiry(struct ibmvscsis_adapter *adapter,
+ struct srp_cmd *cmd, char *data)
+{
+ struct se_portal_group *se_tpg = &adapter->se_tpg;
+ struct inquiry_data *id = (struct inquiry_data *)data;
+ u64 unpacked_lun, lun = cmd->lun;
+ u8 *cdb = cmd->cdb;
+ int len;
+
+ if (!data)
+ printk(KERN_INFO "%s %d: oomu\n", __func__, __LINE__);
+
+ if (((cdb[1] & 0x3) == 0x3) || (!(cdb[1] & 0x3) && cdb[2])) {
+ printk(KERN_INFO "%s %d: invalid req\n", __func__, __LINE__);
+ return 0;
+ }
+
+ if (cdb[1] & 0x3)
+ printk(KERN_INFO "%s %d: needs the normal path\n",
+ __func__, __LINE__);
+ else {
+ id->qual_type = TYPE_DISK;
+ id->rmb_reserve = 0x00;
+ id->version = 0x84; /* ISO/IE */
+ id->aerc_naca_hisup_format = 0x22; /* naca & fmt 0x02 */
+ id->addl_len = sizeof(*id) - 4;
+ id->bque_encserv_vs_multip_mchngr_reserved = 0x00;
+ id->reladr_reserved_linked_cmdqueue_vs = 0x02; /* CMDQ */
+ memcpy(id->vendor, "IBM ", 8);
+ /*
+ * Don't even ask about the next bit. AIX uses
+ * hardcoded device naming to recognize device types
+ * and their client won't work unless we use VOPTA and
+ * VDASD.
+ */
+ if (id->qual_type == TYPE_ROM)
+ memcpy(id->product, "VOPTA blkdev ", 16);
+ else
+ memcpy(id->product, "VDASD blkdev ", 16);
+
+ memcpy(id->revision, "0001", 4);
+
+ snprintf(id->unique, sizeof(id->unique),
+ "IBM-VSCSI-%s-P%d-%x-%d-%d-%d\n",
+ system_id,
+ partition_number,
+ adapter->dma_dev->unit_address,
+ GETBUS(lun),
+ GETTARGET(lun),
+ GETLUN(lun));
+ }
+
+ len = min_t(int, sizeof(*id), cdb[4]);
+
+ unpacked_lun = scsi_lun_to_int(cmd->lun);
+
+ spin_lock(&se_tpg->tpg_lun_lock);
+
+ if (unpacked_lun < TRANSPORT_MAX_LUNS_PER_TPG &&
+ se_tpg->tpg_lun_list[unpacked_lun].lun_status ==
+ TRANSPORT_LUN_STATUS_ACTIVE)
+ ;
+ else
+ data[0] = TYPE_NO_LUN;
+
+ spin_unlock(&se_tpg->tpg_lun_lock);
+
+ return len;
+}
+
+static int ibmvscsis_mode_sense(struct ibmvscsis_adapter *adapter,
+ struct srp_cmd *cmd, char *mode)
+{
+ int bytes;
+ struct se_portal_group *se_tpg = &adapter->se_tpg;
+ u64 unpacked_lun;
+ struct se_lun *lun;
+ u32 blocks;
+
+ unpacked_lun = scsi_lun_to_int(cmd->lun);
+
+ spin_lock(&se_tpg->tpg_lun_lock);
+
+ lun = &se_tpg->tpg_lun_list[unpacked_lun];
+
+ blocks = TRANSPORT(lun->lun_se_dev)->get_blocks(lun->lun_se_dev);
+
+ spin_unlock(&se_tpg->tpg_lun_lock);
+
+ switch (cmd->cdb[2]) {
+ case 0:
+ case 0x3f:
+ mode[1] = 0x00; /* Default medium */
+ /* if (iue->req.vd->b.ro) */
+ if (0)
+ mode[2] = 0x80; /* device specific */
+ else
+ mode[2] = 0x00; /* device specific */
+
+ /* note the DPOFUA bit is set to zero! */
+ mode[3] = 0x08; /* block descriptor length */
+ *((u32 *) &mode[4]) = blocks - 1;
+ *((u32 *) &mode[8]) = 512;
+ bytes = mode[0] = 12; /* length */
+ break;
+
+ case 0x08: /* Cache page */
+ mode[1] = 0x00; /* Default medium */
+ if (0)
+ mode[2] = 0x80; /* device specific */
+ else
+ mode[2] = 0x00; /* device specific */
+
+ /* note the DPOFUA bit is set to zero! */
+ mode[3] = 0x08; /* block descriptor length */
+ *((u32 *) &mode[4]) = blocks - 1;
+ *((u32 *) &mode[8]) = 512;
+
+ /* Cache page */
+ mode[12] = 0x08; /* page */
+ mode[13] = 0x12; /* page length */
+ mode[14] = 0x01; /* no cache (0x04 for read/write cache) */
+
+ bytes = mode[0] = 12 + mode[13]; /* length */
+ break;
+ }
+
+ return bytes;
+}
+
+static int ibmvscsis_report_luns(struct ibmvscsis_adapter *adapter,
+ struct srp_cmd *cmd, u64 *data)
+{
+ u64 lun;
+ struct se_portal_group *se_tpg = &adapter->se_tpg;
+ int i, idx;
+ int alen, oalen, nr_luns, rbuflen = 4096;
+
+ alen = get_unaligned_be32(&cmd->cdb[6]);
+
+ alen &= ~(8 - 1);
+ oalen = alen;
+
+ if (cmd->lun) {
+ nr_luns = 1;
+ goto done;
+ }
+
+ alen -= 8;
+ rbuflen -= 8; /* FIXME */
+ idx = 2;
+ nr_luns = 1;
+
+ spin_lock(&se_tpg->tpg_lun_lock);
+ for (i = 0; i < 255; i++) {
+ if (se_tpg->tpg_lun_list[i].lun_status !=
+ TRANSPORT_LUN_STATUS_ACTIVE)
+ continue;
+
+ lun = make_lun(0, i & 0x003f, 0);
+ data[idx++] = cpu_to_be64(lun);
+ alen -= 8;
+ if (!alen)
+ break;
+ rbuflen -= 8;
+ if (!rbuflen)
+ break;
+
+ nr_luns++;
+ }
+ spin_unlock(&se_tpg->tpg_lun_lock);
+done:
+ put_unaligned_be32(nr_luns * 8, data);
+ return min(oalen, nr_luns * 8 + 8);
+}
+
+static int ibmvscsis_rdma(struct scsi_cmnd *sc, struct scatterlist *sg, int nsg,
+ struct srp_direct_buf *md, int nmd,
+ enum dma_data_direction dir, unsigned int rest)
+{
+ struct iu_entry *iue = (struct iu_entry *) sc->SCp.ptr;
+ struct srp_target *target = iue->target;
+ struct ibmvscsis_adapter *adapter = target->ldata;
+ dma_addr_t token;
+ long err;
+ unsigned int done = 0;
+ int i, sidx, soff;
+
+ sidx = soff = 0;
+ token = sg_dma_address(sg + sidx);
+
+ for (i = 0; i < nmd && rest; i++) {
+ unsigned int mdone, mlen;
+
+ mlen = min(rest, md[i].len);
+ for (mdone = 0; mlen;) {
+ int slen = min(sg_dma_len(sg + sidx) - soff, mlen);
+
+ if (dir == DMA_TO_DEVICE)
+ err = h_copy_rdma(slen,
+ adapter->riobn,
+ md[i].va + mdone,
+ adapter->liobn,
+ token + soff);
+ else
+ err = h_copy_rdma(slen,
+ adapter->liobn,
+ token + soff,
+ adapter->riobn,
+ md[i].va + mdone);
+
+ if (err != H_SUCCESS) {
+ printk(KERN_ERR "rdma error %d %d %ld\n",
+ dir, slen, err);
+ return -EIO;
+ }
+
+ mlen -= slen;
+ mdone += slen;
+ soff += slen;
+ done += slen;
+
+ if (soff == sg_dma_len(sg + sidx)) {
+ sidx++;
+ soff = 0;
+ token = sg_dma_address(sg + sidx);
+
+ if (sidx > nsg) {
+ printk(KERN_ERR "out of sg %p %d %d\n",
+ iue, sidx, nsg);
+ return -EIO;
+ }
+ }
+ };
+
+ rest -= mlen;
+ }
+ return 0;
+}
+
+static int ibmvscsis_cmd_done(struct scsi_cmnd *sc)
+{
+ unsigned long flags;
+ struct iu_entry *iue = (struct iu_entry *) sc->SCp.ptr;
+ struct srp_target *target = iue->target;
+ int err = 0;
+
+ if (scsi_sg_count(sc))
+ err = srp_transfer_data(sc, &vio_iu(iue)->srp.cmd,
+ ibmvscsis_rdma, 1, 1);
+
+ spin_lock_irqsave(&target->lock, flags);
+ list_del(&iue->ilist);
+ spin_unlock_irqrestore(&target->lock, flags);
+
+ if (err || sc->result != SAM_STAT_GOOD) {
+ printk(KERN_ERR "operation failed %p %d %x\n",
+ iue, sc->result, vio_iu(iue)->srp.cmd.cdb[0]);
+ send_rsp(iue, sc, HARDWARE_ERROR, 0x00);
+ } else
+ send_rsp(iue, sc, NO_SENSE, 0x00);
+
+ /* done(sc); */
+ srp_iu_put(iue);
+ return 0;
+}
+
+struct ibmvscsis_cmd {
+ /* Used for libsrp processing callbacks */
+ struct scsi_cmnd sc;
+ /* Used for TCM Core operations */
+ struct se_cmd se_cmd;
+ /* Sense buffer that will be mapped into outgoing status */
+ unsigned char sense_buf[TRANSPORT_SENSE_BUFFER];
+};
+
+static int ibmvscsis_write_pending(struct se_cmd *se_cmd)
+{
+ struct ibmvscsis_cmnd *cmd = container_of(se_cmd,
+ struct ibmvscsis_cmnd, se_cmd);
+ struct scsi_cmnd *sc = &cmd->sc;
+ struct iu_entry *iue = (struct iu_entry *) sc->SCp.ptr;
+ int ret;
+
+ sc->sdb.length = se_cmd->data_length;
+
+ if ((se_cmd->se_cmd_flags & SCF_SCSI_DATA_SG_IO_CDB) ||
+ (se_cmd->se_cmd_flags & SCF_SCSI_CONTROL_SG_IO_CDB)) {
+ transport_do_task_sg_chain(se_cmd);
+
+ sc->sdb.table.nents = T_TASK(se_cmd)->t_tasks_sg_chained_no;
+ sc->sdb.table.sgl = T_TASK(se_cmd)->t_tasks_sg_chained;
+ } else if (se_cmd->se_cmd_flags & SCF_SCSI_CONTROL_NONSG_IO_CDB) {
+ /*
+ * Use T_TASK(se_cmd)->t_tasks_sg_bounce for control CDBs
+ * using a contigious buffer
+ */
+ sg_init_table(&T_TASK(se_cmd)->t_tasks_sg_bounce, 1);
+ sg_set_buf(&T_TASK(se_cmd)->t_tasks_sg_bounce,
+ T_TASK(se_cmd)->t_task_buf, se_cmd->data_length);
+
+ sc->sdb.table.nents = 1;
+ sc->sdb.table.sgl = &T_TASK(se_cmd)->t_tasks_sg_bounce;
+ }
+
+ ret = srp_transfer_data(sc, &vio_iu(iue)->srp.cmd,
+ ibmvscsis_rdma, 1, 1);
+ if (ret) {
+ printk(KERN_ERR "srp_transfer_data() failed: %d\n", ret);
+ return PYX_TRANSPORT_LU_COMM_FAILURE;
+ }
+ /*
+ * We now tell TCM to add this WRITE CDB directly into the TCM storage
+ * object execution queue.
+ */
+ transport_generic_process_write(se_cmd);
+ return 0;
+}
+
+static int ibmvscsis_queue_data_in(struct se_cmd *se_cmd)
+{
+ struct ibmvscsis_cmnd *cmd = container_of(se_cmd,
+ struct ibmvscsis_cmnd, se_cmd);
+ struct scsi_cmnd *sc = &cmd->sc;
+ /*
+ * Check for overflow residual count
+ */
+ if (se_cmd->se_cmd_flags & SCF_OVERFLOW_BIT)
+ scsi_set_resid(sc, se_cmd->residual_count);
+
+ sc->sdb.length = se_cmd->data_length;
+
+ /*
+ * Setup the struct se_task->task_sg[] chained SG list
+ */
+ if ((se_cmd->se_cmd_flags & SCF_SCSI_DATA_SG_IO_CDB) ||
+ (se_cmd->se_cmd_flags & SCF_SCSI_CONTROL_SG_IO_CDB)) {
+ transport_do_task_sg_chain(se_cmd);
+
+ sc->sdb.table.nents = T_TASK(se_cmd)->t_tasks_sg_chained_no;
+ sc->sdb.table.sgl = T_TASK(se_cmd)->t_tasks_sg_chained;
+ } else if (se_cmd->se_cmd_flags & SCF_SCSI_CONTROL_NONSG_IO_CDB) {
+ /*
+ * Use T_TASK(se_cmd)->t_tasks_sg_bounce for control CDBs
+ * using a contigious buffer
+ */
+ sg_init_table(&T_TASK(se_cmd)->t_tasks_sg_bounce, 1);
+ sg_set_buf(&T_TASK(se_cmd)->t_tasks_sg_bounce,
+ T_TASK(se_cmd)->t_task_buf, se_cmd->data_length);
+
+ sc->sdb.table.nents = 1;
+ sc->sdb.table.sgl = &T_TASK(se_cmd)->t_tasks_sg_bounce;
+ }
+ /*
+ * This will call srp_transfer_data() and post the response
+ * to VIO via libsrp.
+ */
+ ibmvscsis_cmd_done(sc);
+ return 0;
+}
+
+static int ibmvscsis_queue_status(struct se_cmd *se_cmd)
+{
+ struct ibmvscsis_cmnd *cmd = container_of(se_cmd,
+ struct ibmvscsis_cmnd, se_cmd);
+ struct scsi_cmnd *sc = &cmd->sc;
+ /*
+ * Copy any generated SENSE data into sc->sense_buffer and
+ * set the appropiate sc->result to be translated by
+ * ibmvscsis_cmd_done()
+ */
+ if (se_cmd->sense_buffer &&
+ ((se_cmd->se_cmd_flags & SCF_TRANSPORT_TASK_SENSE) ||
+ (se_cmd->se_cmd_flags & SCF_EMULATED_TASK_SENSE))) {
+ memcpy((void *)sc->sense_buffer, (void *)se_cmd->sense_buffer,
+ SCSI_SENSE_BUFFERSIZE);
+ sc->result = host_byte(DID_OK) | driver_byte(DRIVER_SENSE) |
+ SAM_STAT_CHECK_CONDITION;
+ } else
+ sc->result = host_byte(DID_OK) | se_cmd->scsi_status;
+ /*
+ * Finally post the response to VIO via libsrp.
+ */
+ ibmvscsis_cmd_done(sc);
+ return 0;
+}
+
+static int ibmvscsis_queuecommand(struct ibmvscsis_adapter *adapter,
+ struct iu_entry *iue)
+{
+ int data_len;
+ struct srp_cmd *cmd = iue->sbuf->buf;
+ struct scsi_cmnd *sc;
+ struct page *pg;
+ struct ibmvscsis_cmnd *vsc;
+
+ data_len = srp_data_length(cmd, srp_cmd_direction(cmd));
+
+ vsc = kzalloc(sizeof(*vsc), GFP_KERNEL);
+ sc = &vsc->sc;
+ sc->sense_buffer = vsc->sense_buf;
+ sc->cmnd = cmd->cdb;
+ sc->SCp.ptr = (char *)iue;
+
+ switch (cmd->cdb[0]) {
+ case INQUIRY:
+ sg_alloc_table(&sc->sdb.table, 1, GFP_KERNEL);
+ pg = alloc_page(GFP_KERNEL|__GFP_ZERO);
+ sc->sdb.length = ibmvscsis_inquiry(adapter, cmd,
+ page_address(pg));
+ sg_set_page(sc->sdb.table.sgl, pg, sc->sdb.length, 0);
+ ibmvscsis_cmd_done(sc);
+ sg_free_table(&sc->sdb.table);
+ __free_page(pg);
+ kfree(vsc);
+ break;
+ case REPORT_LUNS:
+ sg_alloc_table(&sc->sdb.table, 1, GFP_KERNEL);
+ pg = alloc_page(GFP_KERNEL|__GFP_ZERO);
+ sc->sdb.length = ibmvscsis_report_luns(adapter, cmd,
+ page_address(pg));
+ sg_set_page(sc->sdb.table.sgl, pg, sc->sdb.length, 0);
+ ibmvscsis_cmd_done(sc);
+ sg_free_table(&sc->sdb.table);
+ __free_page(pg);
+ kfree(vsc);
+ break;
+ case MODE_SENSE:
+ /* fixme: needs to use tcm */
+ sg_alloc_table(&sc->sdb.table, 1, GFP_KERNEL);
+ pg = alloc_page(GFP_KERNEL|__GFP_ZERO);
+ sc->sdb.length = ibmvscsis_mode_sense(adapter,
+ cmd, page_address(pg));
+ sg_set_page(sc->sdb.table.sgl, pg, sc->sdb.length, 0);
+ ibmvscsis_cmd_done(sc);
+ sg_free_table(&sc->sdb.table);
+ __free_page(pg);
+ kfree(vsc);
+ break;
+ default:
+ tcm_queuecommand(adapter, vsc, cmd);
+ break;
+ }
+
+ return 0;
+}
+
+static void handle_cmd_queue(struct ibmvscsis_adapter *adapter)
+{
+ struct srp_target *target = &adapter->srpt;
+ struct iu_entry *iue;
+ struct srp_cmd *cmd;
+ unsigned long flags;
+ int err;
+
+retry:
+ spin_lock_irqsave(&target->lock, flags);
+
+ list_for_each_entry(iue, &target->cmd_queue, ilist) {
+ if (!test_and_set_bit(V_FLYING, &iue->flags)) {
+ spin_unlock_irqrestore(&target->lock, flags);
+ err = ibmvscsis_queuecommand(adapter, iue);
+ if (err) {
+ printk(KERN_ERR "cannot queue cmd %p %d\n",
+ cmd, err);
+ srp_iu_put(iue);
+ }
+ goto retry;
+ }
+ }
+
+ spin_unlock_irqrestore(&target->lock, flags);
+}
+
+static void handle_crq(struct work_struct *work)
+{
+ struct ibmvscsis_adapter *adapter =
+ container_of(work, struct ibmvscsis_adapter, crq_work);
+ struct viosrp_crq *crq;
+ int done = 0;
+
+ while (!done) {
+ while ((crq = next_crq(&adapter->crq_queue)) != NULL) {
+ process_crq(crq, adapter);
+ crq->valid = 0x00;
+ }
+
+ vio_enable_interrupts(adapter->dma_dev);
+
+ crq = next_crq(&adapter->crq_queue);
+ if (crq) {
+ vio_disable_interrupts(adapter->dma_dev);
+ process_crq(crq, adapter);
+ crq->valid = 0x00;
+ } else
+ done = 1;
+ }
+
+ handle_cmd_queue(adapter);
+}
+
+static irqreturn_t ibmvscsis_interrupt(int dummy, void *data)
+{
+ struct ibmvscsis_adapter *adapter = data;
+
+ vio_disable_interrupts(adapter->dma_dev);
+ schedule_work(&adapter->crq_work);
+
+ return IRQ_HANDLED;
+}
+
+static int crq_queue_create(struct crq_queue *queue,
+ struct ibmvscsis_adapter *adapter)
+{
+ int err;
+ struct vio_dev *vdev = adapter->dma_dev;
+
+ queue->msgs = (struct viosrp_crq *)get_zeroed_page(GFP_KERNEL);
+ if (!queue->msgs)
+ goto malloc_failed;
+ queue->size = PAGE_SIZE / sizeof(*queue->msgs);
+
+ queue->msg_token = dma_map_single(&vdev->dev, queue->msgs,
+ queue->size * sizeof(*queue->msgs),
+ DMA_BIDIRECTIONAL);
+
+ if (dma_mapping_error(&vdev->dev, queue->msg_token))
+ goto map_failed;
+
+ err = h_reg_crq(vdev->unit_address, queue->msg_token,
+ PAGE_SIZE);
+
+ /* If the adapter was left active for some reason (like kexec)
+ * try freeing and re-registering
+ */
+ if (err == H_RESOURCE) {
+ do {
+ err = h_free_crq(vdev->unit_address);
+ } while (err == H_BUSY || H_IS_LONG_BUSY(err));
+
+ err = h_reg_crq(vdev->unit_address, queue->msg_token,
+ PAGE_SIZE);
+ }
+
+ if (err != H_SUCCESS && err != 2) {
+ printk(KERN_ERR "Error 0x%x opening virtual adapter\n", err);
+ goto reg_crq_failed;
+ }
+
+ err = request_irq(vdev->irq, &ibmvscsis_interrupt,
+ IRQF_DISABLED, "ibmvscsis", adapter);
+ if (err)
+ goto req_irq_failed;
+
+ vio_enable_interrupts(vdev);
+
+ h_send_crq(vdev->unit_address, 0xC001000000000000, 0);
+
+ queue->cur = 0;
+ spin_lock_init(&queue->lock);
+
+ return 0;
+
+req_irq_failed:
+ do {
+ err = h_free_crq(vdev->unit_address);
+ } while (err == H_BUSY || H_IS_LONG_BUSY(err));
+
+reg_crq_failed:
+ dma_unmap_single(&vdev->dev, queue->msg_token,
+ queue->size * sizeof(*queue->msgs), DMA_BIDIRECTIONAL);
+map_failed:
+ free_page((unsigned long) queue->msgs);
+
+malloc_failed:
+ return -ENOMEM;
+}
+
+static void crq_queue_destroy(struct ibmvscsis_adapter *adapter)
+{
+ struct crq_queue *queue = &adapter->crq_queue;
+ int err;
+
+ free_irq(adapter->dma_dev->irq, adapter);
+ flush_work_sync(&adapter->crq_work);
+ do {
+ err = h_free_crq(adapter->dma_dev->unit_address);
+ } while (err == H_BUSY || H_IS_LONG_BUSY(err));
+
+ dma_unmap_single(&adapter->dma_dev->dev, queue->msg_token,
+ queue->size * sizeof(*queue->msgs), DMA_BIDIRECTIONAL);
+
+ free_page((unsigned long)queue->msgs);
+}
+
+static int ibmvscsis_probe(struct vio_dev *dev, const struct vio_device_id *id)
+{
+ unsigned int *dma, dma_size;
+ unsigned long flags;
+ int ret;
+ struct ibmvscsis_adapter *adapter;
+
+ adapter = kzalloc(sizeof(*adapter), GFP_KERNEL);
+ if (!adapter)
+ return -ENOMEM;
+
+ adapter->dma_dev = dev;
+
+ dma = (unsigned int *)vio_get_attribute(dev, "ibm,my-dma-window",
+ &dma_size);
+ if (!dma || dma_size != 40) {
+ printk(KERN_ERR "Couldn't get window property %d\n", dma_size);
+ kfree(adapter);
+ return -EIO;
+ }
+
+ adapter->liobn = dma[0];
+ adapter->riobn = dma[5];
+ ret = strict_strtoul(dev_name(&dev->dev), 10, &adapter->tport_tpgt);
+
+ spin_lock_irqsave(&tpg_lock, flags);
+ list_add(&adapter->siblings, &tpg_list);
+ spin_unlock_irqrestore(&tpg_lock, flags);
+
+ INIT_WORK(&adapter->crq_work, handle_crq);
+
+ dev_set_drvdata(&dev->dev, adapter);
+
+ ret = srp_target_alloc(&adapter->srpt, &dev->dev, INITIAL_SRP_LIMIT,
+ SRP_MAX_IU_LEN);
+
+ adapter->srpt.ldata = adapter;
+
+ ret = crq_queue_create(&adapter->crq_queue, adapter);
+
+ return 0;
+}
+
+static int ibmvscsis_remove(struct vio_dev *dev)
+{
+ struct ibmvscsis_adapter *adapter = dev_get_drvdata(&dev->dev);
+ unsigned long flags;
+
+ spin_lock_irqsave(&tpg_lock, flags);
+ list_del(&adapter->siblings);
+ spin_unlock_irqrestore(&tpg_lock, flags);
+
+ crq_queue_destroy(adapter);
+
+ srp_target_free(&adapter->srpt);
+
+ kfree(adapter);
+ return 0;
+}
+
+static struct vio_device_id ibmvscsis_device_table[] __devinitdata = {
+ {"v-scsi-host", "IBM,v-scsi-host"},
+ {"", ""}
+};
+
+MODULE_DEVICE_TABLE(vio, ibmvscsis_device_table);
+
+static struct vio_driver ibmvscsis_driver = {
+ .id_table = ibmvscsis_device_table,
+ .probe = ibmvscsis_probe,
+ .remove = ibmvscsis_remove,
+ .driver = {
+ .name = "ibmvscsis",
+ .owner = THIS_MODULE,
+ }
+};
+
+static int get_system_info(void)
+{
+ struct device_node *rootdn;
+ const char *id, *model, *name;
+ const unsigned int *num;
+
+ rootdn = of_find_node_by_path("/");
+ if (!rootdn)
+ return -ENOENT;
+
+ model = of_get_property(rootdn, "model", NULL);
+ id = of_get_property(rootdn, "system-id", NULL);
+ if (model && id)
+ snprintf(system_id, sizeof(system_id), "%s-%s", model, id);
+
+ name = of_get_property(rootdn, "ibm,partition-name", NULL);
+ if (name)
+ strncpy(partition_name, name, sizeof(partition_name));
+
+ num = of_get_property(rootdn, "ibm,partition-no", NULL);
+ if (num)
+ partition_number = *num;
+
+ of_node_put(rootdn);
+ return 0;
+}
+
+static int ibmvscsis_register_configfs(void)
+{
+ struct target_fabric_configfs *fabric;
+ int ret;
+
+ printk(KERN_INFO "IBMVSCSIS fabric module %s on %s/%s"
+ " on "UTS_RELEASE"\n", IBMVSCSIS_VERSION, utsname()->sysname,
+ utsname()->machine);
+ /*
+ * Register the top level struct config_item_type with TCM core
+ */
+ fabric = target_fabric_configfs_init(THIS_MODULE, "ibmvscsis");
+ if (!(fabric)) {
+ printk(KERN_ERR "target_fabric_configfs_init() failed\n");
+ return -ENOMEM;
+ }
+ /*
+ * Setup fabric->tf_ops from our local ibmvscsis_ops
+ */
+ fabric->tf_ops = ibmvscsis_ops;
+ /*
+ * Setup default attribute lists for various fabric->tf_cit_tmpl
+ */
+ TF_CIT_TMPL(fabric)->tfc_wwn_cit.ct_attrs = ibmvscsis_wwn_attrs;
+ TF_CIT_TMPL(fabric)->tfc_tpg_base_cit.ct_attrs = NULL;
+ TF_CIT_TMPL(fabric)->tfc_tpg_attrib_cit.ct_attrs = NULL;
+ TF_CIT_TMPL(fabric)->tfc_tpg_param_cit.ct_attrs = NULL;
+ TF_CIT_TMPL(fabric)->tfc_tpg_np_base_cit.ct_attrs = NULL;
+ TF_CIT_TMPL(fabric)->tfc_tpg_nacl_base_cit.ct_attrs = NULL;
+ TF_CIT_TMPL(fabric)->tfc_tpg_nacl_attrib_cit.ct_attrs = NULL;
+ TF_CIT_TMPL(fabric)->tfc_tpg_nacl_auth_cit.ct_attrs = NULL;
+ TF_CIT_TMPL(fabric)->tfc_tpg_nacl_param_cit.ct_attrs = NULL;
+ /*
+ * Register the fabric for use within TCM
+ */
+ ret = target_fabric_configfs_register(fabric);
+ if (ret < 0) {
+ printk(KERN_ERR "target_fabric_configfs_register() failed"
+ " for IBMVSCSIS\n");
+ target_fabric_configfs_deregister(fabric);
+ return ret;
+ }
+ /*
+ * Setup our local pointer to *fabric
+ */
+ ibmvscsis_fabric_configfs = fabric;
+ printk(KERN_INFO "IBMVSCSIS[0] - Set fabric -> ibmvscsis_fabric_configfs\n");
+ return 0;
+};
+
+static void ibmvscsis_deregister_configfs(void)
+{
+ if (!(ibmvscsis_fabric_configfs))
+ return;
+
+ target_fabric_configfs_deregister(ibmvscsis_fabric_configfs);
+ ibmvscsis_fabric_configfs = NULL;
+ printk(KERN_INFO "IBMVSCSIS[0] - Cleared ibmvscsis_fabric_configfs\n");
+};
+
+static int __init ibmvscsis_init(void)
+{
+ int ret;
+
+ ret = get_system_info();
+ if (ret)
+ return ret;
+
+ ret = vio_register_driver(&ibmvscsis_driver);
+ if (ret)
+ return ret;
+
+ ret = ibmvscsis_register_configfs();
+ if (ret < 0)
+ return ret;
+
+ return 0;
+};
+
+static void ibmvscsis_exit(void)
+{
+ vio_unregister_driver(&ibmvscsis_driver);
+ ibmvscsis_deregister_configfs();
+};
+
+MODULE_DESCRIPTION("IBMVSCSIS series fabric driver");
+MODULE_AUTHOR("FUJITA Tomonori");
+MODULE_LICENSE("GPL");
+module_init(ibmvscsis_init);
+module_exit(ibmvscsis_exit);
--
1.7.2.3
^ permalink raw reply related
* Re: [PATCH v3 3/3] tcm ibmvscsis driver
From: Nicholas A. Bellinger @ 2011-02-14 10:29 UTC (permalink / raw)
To: FUJITA Tomonori; +Cc: brking, linuxppc-dev, linux-scsi
In-Reply-To: <20110214192600L.fujita.tomonori@lab.ntt.co.jp>
On Mon, 2011-02-14 at 19:25 +0900, FUJITA Tomonori wrote:
> This is the third version of tcm ibmvscsis driver. You can find the
> first version at:
>
> http://marc.info/?t=129734085600004&r=1&w=2
>
> The changes are:
> v3:
> - fix task attribute (convert MSG_* to TASK_ATTR_*)
> v2:
> - send VIOSRP_MAD_NOT_SUPPORTED for unknown mad type requests.
> - fix inquiry typo
> - sends task management response (for now, 'NOT SUPPORTED').
> - remove dead code.
>
> =
> From: FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp>
> Subject: [PATCH v3 3/3] tcm ibmvscsis driver
>
> This replaces ibmvstgt driver that uses the old target framework.
>
> Signed-off-by: FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp>
> ---
> drivers/scsi/ibmvscsi/Makefile | 4 +-
> drivers/scsi/ibmvscsi/ibmvscsis.c | 1761 +++++++++++++++++++++++++++++++++++++
> 2 files changed, 1764 insertions(+), 1 deletions(-)
> create mode 100644 drivers/scsi/ibmvscsi/ibmvscsis.c
>
Merged and pushed your rev3 changes into lio-core-2.6.git/tcm_ibmvscsis
Thanks again Tomo-san!
--nab
^ permalink raw reply
* Re: [PATCH V8 03/10] USB/ppc4xx: Add Synopsys DWC OTG Core InterfaceLayer
From: Alexander Gordeev @ 2011-02-14 11:34 UTC (permalink / raw)
To: David Laight
Cc: Tirumala Marri, Greg KH, linux-usb, Mark Miesfeld, linuxppc-dev,
Fushen Chen
In-Reply-To: <AE90C24D6B3A694183C094C60CF0A2F6D8AC4D@saturn3.aculab.com>
[-- Attachment #1: Type: text/plain, Size: 724 bytes --]
В Mon, 14 Feb 2011 08:53:21 -0000
"David Laight" <David.Laight@ACULAB.COM> пишет:
>
> > > Sorry, I don't understand that. I think u32 is always 32bit
> > > 4byte on all archs. Right?
> >
> > Yes.
> >
> > Use an unsigned long if you want to hold a pointer correctly on all
> > arches.
>
> Although that is true for many systems (and probably all ppc Linux)
> it isn't necessarily true (eg 64 bit Microsoft Windows).
> C99 inttypes.h should define uintptr_t as an unsigned integer
> type that is large enough to hold a (data) pointer.
> I'm not sure if this is defined for the Linux kernel.
I think, the most reasonable option is to use a pointer type to hold
pointer. :)
--
Alexander
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 490 bytes --]
^ permalink raw reply
* Re: [RFC] Inter-processor Mailboxes Drivers
From: Ira W. Snyder @ 2011-02-14 16:53 UTC (permalink / raw)
To: Ohad Ben-Cohen
Cc: Meador Inge, Hiroshi DOYU, Blanchard, Hollis, openmcapi-dev,
Jamie Iles, linuxppc-dev, linux-arm-kernel
In-Reply-To: <AANLkTinu9VMuFgHeFZGXptDYZyJL6P4qxAA9MA8UewpU@mail.gmail.com>
On Mon, Feb 14, 2011 at 12:03:59PM +0200, Ohad Ben-Cohen wrote:
> On Mon, Feb 14, 2011 at 12:01 PM, Jamie Iles <jamie@jamieiles.com> wrote:
> > On Fri, Feb 11, 2011 at 03:19:51PM -0600, Meador Inge wrote:
> >> 1. Hardware specific bits somewhere under '.../arch/*'. Drivers
> >> for the MPIC message registers on Power and OMAP4 mailboxes, for
> >> example.
> >> 2. A higher level driver under '.../drivers/mailbox/*'. That the
> >> pieces in (1) would register with. This piece would expose the
> >> main kernel API.
> >> 3. Userspace interfaces for accessing the mailboxes. A
> >> '/dev/mailbox1', '/dev/mailbox2', etc... mapping, for example.
> >
> > How about using virtio for all of this and having the mailbox as a
> > notification/message passing driver for the virtio backend?
>
> This is exactly what we are doing now, and it looks promising. expect
> patches soon.
I'll be happy to examine the feasibility of doing a port to mpc83xx as
soon as I see the code. :-) I have been using the message registers to
create a software "network card" over PCI (between a host system and an
mpc83xx in a PCI slot). I have wanted to use virtio for this task for a
long time.
I think a uniform interface for the mailbox registers would be a very
useful API.
Thanks,
Ira
^ permalink raw reply
* Re: [PATCH] powerpc: irq_data conversion
From: Grant Likely @ 2011-02-14 18:07 UTC (permalink / raw)
To: Lennert Buytenhek; +Cc: tglx, linuxppc-dev, glikely
In-Reply-To: <20110211125213.GE1240@mail.wantstofly.org>
On Fri, Feb 11, 2011 at 01:52:13PM +0100, Lennert Buytenhek wrote:
> This patch converts powerpc over to the new irq_data based irq_chip
> functions, as was done earlier for ARM and some other architectures.
>
> struct irq_data is described here:
>
> http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=ff7dcd44dd446db2c3e13bdedf2d52b8e0127f16
>
> The new irq_chip functions are described here:
>
> http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=f8822657e799b02c55556c99a601261e207a299d
>
> As I don't have powerpc hardware myself, this hasn't been well-tested
> at all -- build and run-time testing would be much appreciated.
Apply warning:
/home/grant/hacking/linux-2.6/.git/rebase-apply/patch:3470: space before tab in indent.
.irq_mask_ack = uic_mask_ack_irq,
warning: 1 line adds whitespace errors.
It seems to work fine on my ppc32 MPC5200 based Lite5200 board.
Got a build failure from my limited build farm:
02/14 10:38:57 ERROR|base_utils:0106| [stderr] cc1: warnings being treated as errors
02/14 10:38:57 ERROR|base_utils:0106| [stderr] /home/autotest/data/kernelcross/linux/arch/powerpc/platforms/pasemi/setup.c: In function 'pas_init_IRQ':
02/14 10:38:57 ERROR|base_utils:0106| [stderr] /home/autotest/data/kernelcross/linux/arch/powerpc/platforms/pasemi/setup.c:243: error: passing argument 1 of 'mpic_unmask_irq' makes pointer from integer without a cast
02/14 10:38:57 ERROR|base_utils:0106| [stderr] /home/autotest/data/kernelcross/linux/arch/powerpc/include/asm/mpic.h:470: note: expected 'struct irq_data *' but argument is of type 'int'
02/14 10:38:57 ERROR|base_utils:0106| [stderr] /home/autotest/data/kernelcross/linux/arch/powerpc/platforms/pasemi/setup.c: In function 'pas_machine_check_handler':
02/14 10:38:57 ERROR|base_utils:0106| [stderr] /home/autotest/data/kernelcross/linux/arch/powerpc/platforms/pasemi/setup.c:269: error: passing argument 1 of 'mpic_end_irq' makes pointer from integer without a cast
02/14 10:38:57 ERROR|base_utils:0106| [stderr] /home/autotest/data/kernelcross/linux/arch/powerpc/include/asm/mpic.h:474: note: expected 'struct irq_data *' but argument is of type 'int'
02/14 10:38:57 ERROR|base_utils:0106| [stderr] make[3]: *** [arch/powerpc/platforms/pasemi/setup.o] Error 1
I'm running it through the ozlabs build tester:
http://kisskb.ellerman.id.au/kisskb/branch/13/
Results should be available there sometime in the next 6-12 hours
g.
>
> Signed-off-by: Lennert Buytenhek <buytenh@secretlab.ca>
> ---
> arch/powerpc/Kconfig | 1 +
> arch/powerpc/include/asm/mpic.h | 6 +-
> arch/powerpc/include/asm/qe_ic.h | 19 ++--
> arch/powerpc/kernel/irq.c | 23 +++--
> arch/powerpc/kernel/machine_kexec.c | 21 ++--
> arch/powerpc/platforms/512x/mpc5121_ads_cpld.c | 14 ++--
> arch/powerpc/platforms/52xx/media5200.c | 21 ++--
> arch/powerpc/platforms/52xx/mpc52xx_gpt.c | 26 +++---
> arch/powerpc/platforms/52xx/mpc52xx_pic.c | 80 +++++++-------
> arch/powerpc/platforms/82xx/pq2ads-pci-pic.c | 27 +++---
> arch/powerpc/platforms/85xx/ksi8560.c | 3 +-
> arch/powerpc/platforms/85xx/mpc85xx_ads.c | 3 +-
> arch/powerpc/platforms/85xx/mpc85xx_ds.c | 3 +-
> arch/powerpc/platforms/85xx/sbc8560.c | 3 +-
> arch/powerpc/platforms/85xx/socrates_fpga_pic.c | 40 ++++----
> arch/powerpc/platforms/85xx/stx_gp3.c | 3 +-
> arch/powerpc/platforms/85xx/tqm85xx.c | 3 +-
> arch/powerpc/platforms/86xx/gef_pic.c | 22 ++--
> arch/powerpc/platforms/86xx/pic.c | 5 +-
> arch/powerpc/platforms/8xx/m8xx_setup.c | 9 ++-
> arch/powerpc/platforms/cell/axon_msi.c | 3 +-
> arch/powerpc/platforms/cell/beat_interrupt.c | 36 +++---
> arch/powerpc/platforms/cell/interrupt.c | 30 +++---
> arch/powerpc/platforms/cell/setup.c | 6 +-
> arch/powerpc/platforms/cell/spider-pic.c | 43 ++++----
> arch/powerpc/platforms/chrp/setup.c | 5 +-
> arch/powerpc/platforms/embedded6xx/flipper-pic.c | 32 +++---
> arch/powerpc/platforms/embedded6xx/hlwd-pic.c | 41 ++++----
> arch/powerpc/platforms/iseries/irq.c | 43 ++++----
> arch/powerpc/platforms/powermac/pic.c | 48 +++++----
> arch/powerpc/platforms/ps3/interrupt.c | 28 +++---
> arch/powerpc/platforms/pseries/setup.c | 5 +-
> arch/powerpc/platforms/pseries/xics.c | 75 +++++++------
> arch/powerpc/sysdev/cpm1.c | 18 ++--
> arch/powerpc/sysdev/cpm2_pic.c | 32 +++---
> arch/powerpc/sysdev/fsl_msi.c | 19 ++--
> arch/powerpc/sysdev/i8259.c | 42 ++++----
> arch/powerpc/sysdev/ipic.c | 54 +++++-----
> arch/powerpc/sysdev/mpc8xx_pic.c | 32 +++---
> arch/powerpc/sysdev/mpc8xxx_gpio.c | 42 ++++----
> arch/powerpc/sysdev/mpic.c | 127 +++++++++++-----------
> arch/powerpc/sysdev/mpic.h | 5 +-
> arch/powerpc/sysdev/mpic_pasemi_msi.c | 18 ++--
> arch/powerpc/sysdev/mpic_u3msi.c | 18 ++--
> arch/powerpc/sysdev/mv64x60_pic.c | 46 ++++----
> arch/powerpc/sysdev/qe_lib/qe_ic.c | 20 ++--
> arch/powerpc/sysdev/tsi108_pci.c | 41 ++++----
> arch/powerpc/sysdev/uic.c | 59 +++++-----
> arch/powerpc/sysdev/xilinx_intc.c | 48 +++++----
> 49 files changed, 705 insertions(+), 643 deletions(-)
>
> diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
> index 7d69e9b..71ba047 100644
> --- a/arch/powerpc/Kconfig
> +++ b/arch/powerpc/Kconfig
> @@ -134,6 +134,7 @@ config PPC
> select HAVE_GENERIC_HARDIRQS
> select HAVE_SPARSE_IRQ
> select IRQ_PER_CPU
> + select GENERIC_HARDIRQS_NO_DEPRECATED
>
> config EARLY_PRINTK
> bool
> diff --git a/arch/powerpc/include/asm/mpic.h b/arch/powerpc/include/asm/mpic.h
> index e000cce..946ec49 100644
> --- a/arch/powerpc/include/asm/mpic.h
> +++ b/arch/powerpc/include/asm/mpic.h
> @@ -467,11 +467,11 @@ extern void mpic_request_ipis(void);
> void smp_mpic_message_pass(int target, int msg);
>
> /* Unmask a specific virq */
> -extern void mpic_unmask_irq(unsigned int irq);
> +extern void mpic_unmask_irq(struct irq_data *d);
> /* Mask a specific virq */
> -extern void mpic_mask_irq(unsigned int irq);
> +extern void mpic_mask_irq(struct irq_data *d);
> /* EOI a specific virq */
> -extern void mpic_end_irq(unsigned int irq);
> +extern void mpic_end_irq(struct irq_data *d);
>
> /* Fetch interrupt from a given mpic */
> extern unsigned int mpic_get_one_irq(struct mpic *mpic);
> diff --git a/arch/powerpc/include/asm/qe_ic.h b/arch/powerpc/include/asm/qe_ic.h
> index cf51966..9e2cb20 100644
> --- a/arch/powerpc/include/asm/qe_ic.h
> +++ b/arch/powerpc/include/asm/qe_ic.h
> @@ -81,7 +81,7 @@ int qe_ic_set_high_priority(unsigned int virq, unsigned int priority, int high);
> static inline void qe_ic_cascade_low_ipic(unsigned int irq,
> struct irq_desc *desc)
> {
> - struct qe_ic *qe_ic = desc->handler_data;
> + struct qe_ic *qe_ic = get_irq_desc_data(desc);
> unsigned int cascade_irq = qe_ic_get_low_irq(qe_ic);
>
> if (cascade_irq != NO_IRQ)
> @@ -91,7 +91,7 @@ static inline void qe_ic_cascade_low_ipic(unsigned int irq,
> static inline void qe_ic_cascade_high_ipic(unsigned int irq,
> struct irq_desc *desc)
> {
> - struct qe_ic *qe_ic = desc->handler_data;
> + struct qe_ic *qe_ic = get_irq_desc_data(desc);
> unsigned int cascade_irq = qe_ic_get_high_irq(qe_ic);
>
> if (cascade_irq != NO_IRQ)
> @@ -101,32 +101,35 @@ static inline void qe_ic_cascade_high_ipic(unsigned int irq,
> static inline void qe_ic_cascade_low_mpic(unsigned int irq,
> struct irq_desc *desc)
> {
> - struct qe_ic *qe_ic = desc->handler_data;
> + struct qe_ic *qe_ic = get_irq_desc_data(desc);
> unsigned int cascade_irq = qe_ic_get_low_irq(qe_ic);
> + struct irq_chip *chip = get_irq_desc_chip(desc);
>
> if (cascade_irq != NO_IRQ)
> generic_handle_irq(cascade_irq);
>
> - desc->chip->eoi(irq);
> + chip->irq_eoi(&desc->irq_data);
> }
>
> static inline void qe_ic_cascade_high_mpic(unsigned int irq,
> struct irq_desc *desc)
> {
> - struct qe_ic *qe_ic = desc->handler_data;
> + struct qe_ic *qe_ic = get_irq_desc_data(desc);
> unsigned int cascade_irq = qe_ic_get_high_irq(qe_ic);
> + struct irq_chip *chip = get_irq_desc_chip(desc);
>
> if (cascade_irq != NO_IRQ)
> generic_handle_irq(cascade_irq);
>
> - desc->chip->eoi(irq);
> + chip->irq_eoi(&desc->irq_data);
> }
>
> static inline void qe_ic_cascade_muxed_mpic(unsigned int irq,
> struct irq_desc *desc)
> {
> - struct qe_ic *qe_ic = desc->handler_data;
> + struct qe_ic *qe_ic = get_irq_desc_data(desc);
> unsigned int cascade_irq;
> + struct irq_chip *chip = get_irq_desc_chip(desc);
>
> cascade_irq = qe_ic_get_high_irq(qe_ic);
> if (cascade_irq == NO_IRQ)
> @@ -135,7 +138,7 @@ static inline void qe_ic_cascade_muxed_mpic(unsigned int irq,
> if (cascade_irq != NO_IRQ)
> generic_handle_irq(cascade_irq);
>
> - desc->chip->eoi(irq);
> + chip->irq_eoi(&desc->irq_data);
> }
>
> #endif /* _ASM_POWERPC_QE_IC_H */
> diff --git a/arch/powerpc/kernel/irq.c b/arch/powerpc/kernel/irq.c
> index ce557f6..4a9fa84 100644
> --- a/arch/powerpc/kernel/irq.c
> +++ b/arch/powerpc/kernel/irq.c
> @@ -237,6 +237,7 @@ int show_interrupts(struct seq_file *p, void *v)
> int i = *(loff_t *) v, j, prec;
> struct irqaction *action;
> struct irq_desc *desc;
> + struct irq_chip *chip;
>
> if (i > nr_irqs)
> return 0;
> @@ -270,8 +271,9 @@ int show_interrupts(struct seq_file *p, void *v)
> for_each_online_cpu(j)
> seq_printf(p, "%10u ", kstat_irqs_cpu(i, j));
>
> - if (desc->chip)
> - seq_printf(p, " %-16s", desc->chip->name);
> + chip = get_irq_desc_chip(desc);
> + if (chip)
> + seq_printf(p, " %-16s", chip->name);
> else
> seq_printf(p, " %-16s", "None");
> seq_printf(p, " %-8s", (desc->status & IRQ_LEVEL) ? "Level" : "Edge");
> @@ -313,6 +315,8 @@ void fixup_irqs(const struct cpumask *map)
> alloc_cpumask_var(&mask, GFP_KERNEL);
>
> for_each_irq(irq) {
> + struct irq_chip *chip;
> +
> desc = irq_to_desc(irq);
> if (!desc)
> continue;
> @@ -320,13 +324,15 @@ void fixup_irqs(const struct cpumask *map)
> if (desc->status & IRQ_PER_CPU)
> continue;
>
> - cpumask_and(mask, desc->affinity, map);
> + chip = get_irq_desc_chip(desc);
> +
> + cpumask_and(mask, desc->irq_data.affinity, map);
> if (cpumask_any(mask) >= nr_cpu_ids) {
> printk("Breaking affinity for irq %i\n", irq);
> cpumask_copy(mask, map);
> }
> - if (desc->chip->set_affinity)
> - desc->chip->set_affinity(irq, mask);
> + if (chip->irq_set_affinity)
> + chip->irq_set_affinity(&desc->irq_data, mask, true);
> else if (desc->action && !(warned++))
> printk("Cannot set affinity for irq %i\n", irq);
> }
> @@ -1159,11 +1165,14 @@ static int virq_debug_show(struct seq_file *m, void *private)
> raw_spin_lock_irqsave(&desc->lock, flags);
>
> if (desc->action && desc->action->handler) {
> + struct irq_chip *chip;
> +
> seq_printf(m, "%5d ", i);
> seq_printf(m, "0x%05lx ", virq_to_hw(i));
>
> - if (desc->chip && desc->chip->name)
> - p = desc->chip->name;
> + chip = get_irq_desc_chip(desc);
> + if (chip && chip->name)
> + p = chip->name;
> else
> p = none;
> seq_printf(m, "%-15s ", p);
> diff --git a/arch/powerpc/kernel/machine_kexec.c b/arch/powerpc/kernel/machine_kexec.c
> index 49a170a..976de37 100644
> --- a/arch/powerpc/kernel/machine_kexec.c
> +++ b/arch/powerpc/kernel/machine_kexec.c
> @@ -26,20 +26,23 @@ void machine_kexec_mask_interrupts(void) {
>
> for_each_irq(i) {
> struct irq_desc *desc = irq_to_desc(i);
> + struct irq_chip *chip;
>
> - if (!desc || !desc->chip)
> + if (!desc)
> continue;
>
> - if (desc->chip->eoi &&
> - desc->status & IRQ_INPROGRESS)
> - desc->chip->eoi(i);
> + chip = get_irq_desc_chip(desc);
> + if (!chip)
> + continue;
> +
> + if (chip->irq_eoi && desc->status & IRQ_INPROGRESS)
> + chip->irq_eoi(&desc->irq_data);
>
> - if (desc->chip->mask)
> - desc->chip->mask(i);
> + if (chip->irq_mask)
> + chip->irq_mask(&desc->irq_data);
>
> - if (desc->chip->disable &&
> - !(desc->status & IRQ_DISABLED))
> - desc->chip->disable(i);
> + if (chip->irq_disable && !(desc->status & IRQ_DISABLED))
> + chip->irq_disable(&desc->irq_data);
> }
> }
>
> diff --git a/arch/powerpc/platforms/512x/mpc5121_ads_cpld.c b/arch/powerpc/platforms/512x/mpc5121_ads_cpld.c
> index 4ecf4cf..fde0ea5 100644
> --- a/arch/powerpc/platforms/512x/mpc5121_ads_cpld.c
> +++ b/arch/powerpc/platforms/512x/mpc5121_ads_cpld.c
> @@ -59,9 +59,9 @@ irq_to_pic_bit(unsigned int irq)
> }
>
> static void
> -cpld_mask_irq(unsigned int irq)
> +cpld_mask_irq(struct irq_data *d)
> {
> - unsigned int cpld_irq = (unsigned int)irq_map[irq].hwirq;
> + unsigned int cpld_irq = (unsigned int)irq_map[d->irq].hwirq;
> void __iomem *pic_mask = irq_to_pic_mask(cpld_irq);
>
> out_8(pic_mask,
> @@ -69,9 +69,9 @@ cpld_mask_irq(unsigned int irq)
> }
>
> static void
> -cpld_unmask_irq(unsigned int irq)
> +cpld_unmask_irq(struct irq_data *d)
> {
> - unsigned int cpld_irq = (unsigned int)irq_map[irq].hwirq;
> + unsigned int cpld_irq = (unsigned int)irq_map[d->irq].hwirq;
> void __iomem *pic_mask = irq_to_pic_mask(cpld_irq);
>
> out_8(pic_mask,
> @@ -80,9 +80,9 @@ cpld_unmask_irq(unsigned int irq)
>
> static struct irq_chip cpld_pic = {
> .name = "CPLD PIC",
> - .mask = cpld_mask_irq,
> - .ack = cpld_mask_irq,
> - .unmask = cpld_unmask_irq,
> + .irq_mask = cpld_mask_irq,
> + .irq_ack = cpld_mask_irq,
> + .irq_unmask = cpld_unmask_irq,
> };
>
> static int
> diff --git a/arch/powerpc/platforms/52xx/media5200.c b/arch/powerpc/platforms/52xx/media5200.c
> index 2c7780c..2bd1e6c 100644
> --- a/arch/powerpc/platforms/52xx/media5200.c
> +++ b/arch/powerpc/platforms/52xx/media5200.c
> @@ -49,45 +49,46 @@ struct media5200_irq {
> };
> struct media5200_irq media5200_irq;
>
> -static void media5200_irq_unmask(unsigned int virq)
> +static void media5200_irq_unmask(struct irq_data *d)
> {
> unsigned long flags;
> u32 val;
>
> spin_lock_irqsave(&media5200_irq.lock, flags);
> val = in_be32(media5200_irq.regs + MEDIA5200_IRQ_ENABLE);
> - val |= 1 << (MEDIA5200_IRQ_SHIFT + irq_map[virq].hwirq);
> + val |= 1 << (MEDIA5200_IRQ_SHIFT + irq_map[d->irq].hwirq);
> out_be32(media5200_irq.regs + MEDIA5200_IRQ_ENABLE, val);
> spin_unlock_irqrestore(&media5200_irq.lock, flags);
> }
>
> -static void media5200_irq_mask(unsigned int virq)
> +static void media5200_irq_mask(struct irq_data *d)
> {
> unsigned long flags;
> u32 val;
>
> spin_lock_irqsave(&media5200_irq.lock, flags);
> val = in_be32(media5200_irq.regs + MEDIA5200_IRQ_ENABLE);
> - val &= ~(1 << (MEDIA5200_IRQ_SHIFT + irq_map[virq].hwirq));
> + val &= ~(1 << (MEDIA5200_IRQ_SHIFT + irq_map[d->irq].hwirq));
> out_be32(media5200_irq.regs + MEDIA5200_IRQ_ENABLE, val);
> spin_unlock_irqrestore(&media5200_irq.lock, flags);
> }
>
> static struct irq_chip media5200_irq_chip = {
> .name = "Media5200 FPGA",
> - .unmask = media5200_irq_unmask,
> - .mask = media5200_irq_mask,
> - .mask_ack = media5200_irq_mask,
> + .irq_unmask = media5200_irq_unmask,
> + .irq_mask = media5200_irq_mask,
> + .irq_mask_ack = media5200_irq_mask,
> };
>
> void media5200_irq_cascade(unsigned int virq, struct irq_desc *desc)
> {
> + struct irq_chip *chip = get_irq_desc_chip(desc);
> int sub_virq, val;
> u32 status, enable;
>
> /* Mask off the cascaded IRQ */
> raw_spin_lock(&desc->lock);
> - desc->chip->mask(virq);
> + chip->irq_mask(&desc->irq_data);
> raw_spin_unlock(&desc->lock);
>
> /* Ask the FPGA for IRQ status. If 'val' is 0, then no irqs
> @@ -105,9 +106,9 @@ void media5200_irq_cascade(unsigned int virq, struct irq_desc *desc)
>
> /* Processing done; can reenable the cascade now */
> raw_spin_lock(&desc->lock);
> - desc->chip->ack(virq);
> + chip->irq_ack(&desc->irq_data);
> if (!(desc->status & IRQ_DISABLED))
> - desc->chip->unmask(virq);
> + chip->irq_unmask(&desc->irq_data);
> raw_spin_unlock(&desc->lock);
> }
>
> diff --git a/arch/powerpc/platforms/52xx/mpc52xx_gpt.c b/arch/powerpc/platforms/52xx/mpc52xx_gpt.c
> index e0d703c..fe6cc5d 100644
> --- a/arch/powerpc/platforms/52xx/mpc52xx_gpt.c
> +++ b/arch/powerpc/platforms/52xx/mpc52xx_gpt.c
> @@ -135,9 +135,9 @@ DEFINE_MUTEX(mpc52xx_gpt_list_mutex);
> * Cascaded interrupt controller hooks
> */
>
> -static void mpc52xx_gpt_irq_unmask(unsigned int virq)
> +static void mpc52xx_gpt_irq_unmask(struct irq_data *d)
> {
> - struct mpc52xx_gpt_priv *gpt = get_irq_chip_data(virq);
> + struct mpc52xx_gpt_priv *gpt = get_irq_chip_data(d->irq);
> unsigned long flags;
>
> spin_lock_irqsave(&gpt->lock, flags);
> @@ -145,9 +145,9 @@ static void mpc52xx_gpt_irq_unmask(unsigned int virq)
> spin_unlock_irqrestore(&gpt->lock, flags);
> }
>
> -static void mpc52xx_gpt_irq_mask(unsigned int virq)
> +static void mpc52xx_gpt_irq_mask(struct irq_data *d)
> {
> - struct mpc52xx_gpt_priv *gpt = get_irq_chip_data(virq);
> + struct mpc52xx_gpt_priv *gpt = get_irq_chip_data(d->irq);
> unsigned long flags;
>
> spin_lock_irqsave(&gpt->lock, flags);
> @@ -155,20 +155,20 @@ static void mpc52xx_gpt_irq_mask(unsigned int virq)
> spin_unlock_irqrestore(&gpt->lock, flags);
> }
>
> -static void mpc52xx_gpt_irq_ack(unsigned int virq)
> +static void mpc52xx_gpt_irq_ack(struct irq_data *d)
> {
> - struct mpc52xx_gpt_priv *gpt = get_irq_chip_data(virq);
> + struct mpc52xx_gpt_priv *gpt = get_irq_chip_data(d->irq);
>
> out_be32(&gpt->regs->status, MPC52xx_GPT_STATUS_IRQMASK);
> }
>
> -static int mpc52xx_gpt_irq_set_type(unsigned int virq, unsigned int flow_type)
> +static int mpc52xx_gpt_irq_set_type(struct irq_data *d, unsigned int flow_type)
> {
> - struct mpc52xx_gpt_priv *gpt = get_irq_chip_data(virq);
> + struct mpc52xx_gpt_priv *gpt = get_irq_chip_data(d->irq);
> unsigned long flags;
> u32 reg;
>
> - dev_dbg(gpt->dev, "%s: virq=%i type=%x\n", __func__, virq, flow_type);
> + dev_dbg(gpt->dev, "%s: virq=%i type=%x\n", __func__, d->irq, flow_type);
>
> spin_lock_irqsave(&gpt->lock, flags);
> reg = in_be32(&gpt->regs->mode) & ~MPC52xx_GPT_MODE_ICT_MASK;
> @@ -184,10 +184,10 @@ static int mpc52xx_gpt_irq_set_type(unsigned int virq, unsigned int flow_type)
>
> static struct irq_chip mpc52xx_gpt_irq_chip = {
> .name = "MPC52xx GPT",
> - .unmask = mpc52xx_gpt_irq_unmask,
> - .mask = mpc52xx_gpt_irq_mask,
> - .ack = mpc52xx_gpt_irq_ack,
> - .set_type = mpc52xx_gpt_irq_set_type,
> + .irq_unmask = mpc52xx_gpt_irq_unmask,
> + .irq_mask = mpc52xx_gpt_irq_mask,
> + .irq_ack = mpc52xx_gpt_irq_ack,
> + .irq_set_type = mpc52xx_gpt_irq_set_type,
> };
>
> void mpc52xx_gpt_irq_cascade(unsigned int virq, struct irq_desc *desc)
> diff --git a/arch/powerpc/platforms/52xx/mpc52xx_pic.c b/arch/powerpc/platforms/52xx/mpc52xx_pic.c
> index 4bf4bf7..9f3ed58 100644
> --- a/arch/powerpc/platforms/52xx/mpc52xx_pic.c
> +++ b/arch/powerpc/platforms/52xx/mpc52xx_pic.c
> @@ -155,47 +155,47 @@ static inline void io_be_clrbit(u32 __iomem *addr, int bitno)
> /*
> * IRQ[0-3] interrupt irq_chip
> */
> -static void mpc52xx_extirq_mask(unsigned int virq)
> +static void mpc52xx_extirq_mask(struct irq_data *d)
> {
> int irq;
> int l2irq;
>
> - irq = irq_map[virq].hwirq;
> + irq = irq_map[d->irq].hwirq;
> l2irq = irq & MPC52xx_IRQ_L2_MASK;
>
> io_be_clrbit(&intr->ctrl, 11 - l2irq);
> }
>
> -static void mpc52xx_extirq_unmask(unsigned int virq)
> +static void mpc52xx_extirq_unmask(struct irq_data *d)
> {
> int irq;
> int l2irq;
>
> - irq = irq_map[virq].hwirq;
> + irq = irq_map[d->irq].hwirq;
> l2irq = irq & MPC52xx_IRQ_L2_MASK;
>
> io_be_setbit(&intr->ctrl, 11 - l2irq);
> }
>
> -static void mpc52xx_extirq_ack(unsigned int virq)
> +static void mpc52xx_extirq_ack(struct irq_data *d)
> {
> int irq;
> int l2irq;
>
> - irq = irq_map[virq].hwirq;
> + irq = irq_map[d->irq].hwirq;
> l2irq = irq & MPC52xx_IRQ_L2_MASK;
>
> io_be_setbit(&intr->ctrl, 27-l2irq);
> }
>
> -static int mpc52xx_extirq_set_type(unsigned int virq, unsigned int flow_type)
> +static int mpc52xx_extirq_set_type(struct irq_data *d, unsigned int flow_type)
> {
> u32 ctrl_reg, type;
> int irq;
> int l2irq;
> void *handler = handle_level_irq;
>
> - irq = irq_map[virq].hwirq;
> + irq = irq_map[d->irq].hwirq;
> l2irq = irq & MPC52xx_IRQ_L2_MASK;
>
> pr_debug("%s: irq=%x. l2=%d flow_type=%d\n", __func__, irq, l2irq, flow_type);
> @@ -214,44 +214,44 @@ static int mpc52xx_extirq_set_type(unsigned int virq, unsigned int flow_type)
> ctrl_reg |= (type << (22 - (l2irq * 2)));
> out_be32(&intr->ctrl, ctrl_reg);
>
> - __set_irq_handler_unlocked(virq, handler);
> + __set_irq_handler_unlocked(d->irq, handler);
>
> return 0;
> }
>
> static struct irq_chip mpc52xx_extirq_irqchip = {
> .name = "MPC52xx External",
> - .mask = mpc52xx_extirq_mask,
> - .unmask = mpc52xx_extirq_unmask,
> - .ack = mpc52xx_extirq_ack,
> - .set_type = mpc52xx_extirq_set_type,
> + .irq_mask = mpc52xx_extirq_mask,
> + .irq_unmask = mpc52xx_extirq_unmask,
> + .irq_ack = mpc52xx_extirq_ack,
> + .irq_set_type = mpc52xx_extirq_set_type,
> };
>
> /*
> * Main interrupt irq_chip
> */
> -static int mpc52xx_null_set_type(unsigned int virq, unsigned int flow_type)
> +static int mpc52xx_null_set_type(struct irq_data *d, unsigned int flow_type)
> {
> return 0; /* Do nothing so that the sense mask will get updated */
> }
>
> -static void mpc52xx_main_mask(unsigned int virq)
> +static void mpc52xx_main_mask(struct irq_data *d)
> {
> int irq;
> int l2irq;
>
> - irq = irq_map[virq].hwirq;
> + irq = irq_map[d->irq].hwirq;
> l2irq = irq & MPC52xx_IRQ_L2_MASK;
>
> io_be_setbit(&intr->main_mask, 16 - l2irq);
> }
>
> -static void mpc52xx_main_unmask(unsigned int virq)
> +static void mpc52xx_main_unmask(struct irq_data *d)
> {
> int irq;
> int l2irq;
>
> - irq = irq_map[virq].hwirq;
> + irq = irq_map[d->irq].hwirq;
> l2irq = irq & MPC52xx_IRQ_L2_MASK;
>
> io_be_clrbit(&intr->main_mask, 16 - l2irq);
> @@ -259,32 +259,32 @@ static void mpc52xx_main_unmask(unsigned int virq)
>
> static struct irq_chip mpc52xx_main_irqchip = {
> .name = "MPC52xx Main",
> - .mask = mpc52xx_main_mask,
> - .mask_ack = mpc52xx_main_mask,
> - .unmask = mpc52xx_main_unmask,
> - .set_type = mpc52xx_null_set_type,
> + .irq_mask = mpc52xx_main_mask,
> + .irq_mask_ack = mpc52xx_main_mask,
> + .irq_unmask = mpc52xx_main_unmask,
> + .irq_set_type = mpc52xx_null_set_type,
> };
>
> /*
> * Peripherals interrupt irq_chip
> */
> -static void mpc52xx_periph_mask(unsigned int virq)
> +static void mpc52xx_periph_mask(struct irq_data *d)
> {
> int irq;
> int l2irq;
>
> - irq = irq_map[virq].hwirq;
> + irq = irq_map[d->irq].hwirq;
> l2irq = irq & MPC52xx_IRQ_L2_MASK;
>
> io_be_setbit(&intr->per_mask, 31 - l2irq);
> }
>
> -static void mpc52xx_periph_unmask(unsigned int virq)
> +static void mpc52xx_periph_unmask(struct irq_data *d)
> {
> int irq;
> int l2irq;
>
> - irq = irq_map[virq].hwirq;
> + irq = irq_map[d->irq].hwirq;
> l2irq = irq & MPC52xx_IRQ_L2_MASK;
>
> io_be_clrbit(&intr->per_mask, 31 - l2irq);
> @@ -292,43 +292,43 @@ static void mpc52xx_periph_unmask(unsigned int virq)
>
> static struct irq_chip mpc52xx_periph_irqchip = {
> .name = "MPC52xx Peripherals",
> - .mask = mpc52xx_periph_mask,
> - .mask_ack = mpc52xx_periph_mask,
> - .unmask = mpc52xx_periph_unmask,
> - .set_type = mpc52xx_null_set_type,
> + .irq_mask = mpc52xx_periph_mask,
> + .irq_mask_ack = mpc52xx_periph_mask,
> + .irq_unmask = mpc52xx_periph_unmask,
> + .irq_set_type = mpc52xx_null_set_type,
> };
>
> /*
> * SDMA interrupt irq_chip
> */
> -static void mpc52xx_sdma_mask(unsigned int virq)
> +static void mpc52xx_sdma_mask(struct irq_data *d)
> {
> int irq;
> int l2irq;
>
> - irq = irq_map[virq].hwirq;
> + irq = irq_map[d->irq].hwirq;
> l2irq = irq & MPC52xx_IRQ_L2_MASK;
>
> io_be_setbit(&sdma->IntMask, l2irq);
> }
>
> -static void mpc52xx_sdma_unmask(unsigned int virq)
> +static void mpc52xx_sdma_unmask(struct irq_data *d)
> {
> int irq;
> int l2irq;
>
> - irq = irq_map[virq].hwirq;
> + irq = irq_map[d->irq].hwirq;
> l2irq = irq & MPC52xx_IRQ_L2_MASK;
>
> io_be_clrbit(&sdma->IntMask, l2irq);
> }
>
> -static void mpc52xx_sdma_ack(unsigned int virq)
> +static void mpc52xx_sdma_ack(struct irq_data *d)
> {
> int irq;
> int l2irq;
>
> - irq = irq_map[virq].hwirq;
> + irq = irq_map[d->irq].hwirq;
> l2irq = irq & MPC52xx_IRQ_L2_MASK;
>
> out_be32(&sdma->IntPend, 1 << l2irq);
> @@ -336,10 +336,10 @@ static void mpc52xx_sdma_ack(unsigned int virq)
>
> static struct irq_chip mpc52xx_sdma_irqchip = {
> .name = "MPC52xx SDMA",
> - .mask = mpc52xx_sdma_mask,
> - .unmask = mpc52xx_sdma_unmask,
> - .ack = mpc52xx_sdma_ack,
> - .set_type = mpc52xx_null_set_type,
> + .irq_mask = mpc52xx_sdma_mask,
> + .irq_unmask = mpc52xx_sdma_unmask,
> + .irq_ack = mpc52xx_sdma_ack,
> + .irq_set_type = mpc52xx_null_set_type,
> };
>
> /**
> diff --git a/arch/powerpc/platforms/82xx/pq2ads-pci-pic.c b/arch/powerpc/platforms/82xx/pq2ads-pci-pic.c
> index 5a55d87..a0cd8ae 100644
> --- a/arch/powerpc/platforms/82xx/pq2ads-pci-pic.c
> +++ b/arch/powerpc/platforms/82xx/pq2ads-pci-pic.c
> @@ -39,10 +39,10 @@ struct pq2ads_pci_pic {
>
> #define NUM_IRQS 32
>
> -static void pq2ads_pci_mask_irq(unsigned int virq)
> +static void pq2ads_pci_mask_irq(struct irq_data *d)
> {
> - struct pq2ads_pci_pic *priv = get_irq_chip_data(virq);
> - int irq = NUM_IRQS - virq_to_hw(virq) - 1;
> + struct pq2ads_pci_pic *priv = get_irq_chip_data(d->irq);
> + int irq = NUM_IRQS - virq_to_hw(d->irq) - 1;
>
> if (irq != -1) {
> unsigned long flags;
> @@ -55,10 +55,10 @@ static void pq2ads_pci_mask_irq(unsigned int virq)
> }
> }
>
> -static void pq2ads_pci_unmask_irq(unsigned int virq)
> +static void pq2ads_pci_unmask_irq(struct irq_data *d)
> {
> - struct pq2ads_pci_pic *priv = get_irq_chip_data(virq);
> - int irq = NUM_IRQS - virq_to_hw(virq) - 1;
> + struct pq2ads_pci_pic *priv = get_irq_chip_data(d->irq);
> + int irq = NUM_IRQS - virq_to_hw(d->irq) - 1;
>
> if (irq != -1) {
> unsigned long flags;
> @@ -71,18 +71,17 @@ static void pq2ads_pci_unmask_irq(unsigned int virq)
>
> static struct irq_chip pq2ads_pci_ic = {
> .name = "PQ2 ADS PCI",
> - .end = pq2ads_pci_unmask_irq,
> - .mask = pq2ads_pci_mask_irq,
> - .mask_ack = pq2ads_pci_mask_irq,
> - .ack = pq2ads_pci_mask_irq,
> - .unmask = pq2ads_pci_unmask_irq,
> - .enable = pq2ads_pci_unmask_irq,
> - .disable = pq2ads_pci_mask_irq
> + .irq_mask = pq2ads_pci_mask_irq,
> + .irq_mask_ack = pq2ads_pci_mask_irq,
> + .irq_ack = pq2ads_pci_mask_irq,
> + .irq_unmask = pq2ads_pci_unmask_irq,
> + .irq_enable = pq2ads_pci_unmask_irq,
> + .irq_disable = pq2ads_pci_mask_irq
> };
>
> static void pq2ads_pci_irq_demux(unsigned int irq, struct irq_desc *desc)
> {
> - struct pq2ads_pci_pic *priv = desc->handler_data;
> + struct pq2ads_pci_pic *priv = get_irq_desc_data(desc);
> u32 stat, mask, pend;
> int bit;
>
> diff --git a/arch/powerpc/platforms/85xx/ksi8560.c b/arch/powerpc/platforms/85xx/ksi8560.c
> index f4d36b5..64447e4 100644
> --- a/arch/powerpc/platforms/85xx/ksi8560.c
> +++ b/arch/powerpc/platforms/85xx/ksi8560.c
> @@ -56,12 +56,13 @@ static void machine_restart(char *cmd)
>
> static void cpm2_cascade(unsigned int irq, struct irq_desc *desc)
> {
> + struct irq_chip *chip = get_irq_desc_chip(desc);
> int cascade_irq;
>
> while ((cascade_irq = cpm2_get_irq()) >= 0)
> generic_handle_irq(cascade_irq);
>
> - desc->chip->eoi(irq);
> + chip->irq_eoi(&desc->irq_data);
> }
>
> static void __init ksi8560_pic_init(void)
> diff --git a/arch/powerpc/platforms/85xx/mpc85xx_ads.c b/arch/powerpc/platforms/85xx/mpc85xx_ads.c
> index 9438a89..1352d11 100644
> --- a/arch/powerpc/platforms/85xx/mpc85xx_ads.c
> +++ b/arch/powerpc/platforms/85xx/mpc85xx_ads.c
> @@ -50,12 +50,13 @@ static int mpc85xx_exclude_device(struct pci_controller *hose,
>
> static void cpm2_cascade(unsigned int irq, struct irq_desc *desc)
> {
> + struct irq_chip *chip = get_irq_desc_chip(desc);
> int cascade_irq;
>
> while ((cascade_irq = cpm2_get_irq()) >= 0)
> generic_handle_irq(cascade_irq);
>
> - desc->chip->eoi(irq);
> + chip->irq_eoi(&desc->irq_data);
> }
>
> #endif /* CONFIG_CPM2 */
> diff --git a/arch/powerpc/platforms/85xx/mpc85xx_ds.c b/arch/powerpc/platforms/85xx/mpc85xx_ds.c
> index 8190bc2..793ead7 100644
> --- a/arch/powerpc/platforms/85xx/mpc85xx_ds.c
> +++ b/arch/powerpc/platforms/85xx/mpc85xx_ds.c
> @@ -47,12 +47,13 @@
> #ifdef CONFIG_PPC_I8259
> static void mpc85xx_8259_cascade(unsigned int irq, struct irq_desc *desc)
> {
> + struct irq_chip *chip = get_irq_desc_chip(desc);
> unsigned int cascade_irq = i8259_irq();
>
> if (cascade_irq != NO_IRQ) {
> generic_handle_irq(cascade_irq);
> }
> - desc->chip->eoi(irq);
> + chip->irq_eoi(&desc->irq_data);
> }
> #endif /* CONFIG_PPC_I8259 */
>
> diff --git a/arch/powerpc/platforms/85xx/sbc8560.c b/arch/powerpc/platforms/85xx/sbc8560.c
> index a5ad1c7..d7e28ec 100644
> --- a/arch/powerpc/platforms/85xx/sbc8560.c
> +++ b/arch/powerpc/platforms/85xx/sbc8560.c
> @@ -41,12 +41,13 @@
>
> static void cpm2_cascade(unsigned int irq, struct irq_desc *desc)
> {
> + struct irq_chip *chip = get_irq_desc_chip(desc);
> int cascade_irq;
>
> while ((cascade_irq = cpm2_get_irq()) >= 0)
> generic_handle_irq(cascade_irq);
>
> - desc->chip->eoi(irq);
> + chip->irq_eoi(&desc->irq_data);
> }
>
> #endif /* CONFIG_CPM2 */
> diff --git a/arch/powerpc/platforms/85xx/socrates_fpga_pic.c b/arch/powerpc/platforms/85xx/socrates_fpga_pic.c
> index d48527f..79d85ac 100644
> --- a/arch/powerpc/platforms/85xx/socrates_fpga_pic.c
> +++ b/arch/powerpc/platforms/85xx/socrates_fpga_pic.c
> @@ -93,6 +93,7 @@ static inline unsigned int socrates_fpga_pic_get_irq(unsigned int irq)
>
> void socrates_fpga_pic_cascade(unsigned int irq, struct irq_desc *desc)
> {
> + struct irq_chip *chip = get_irq_desc_chip(desc);
> unsigned int cascade_irq;
>
> /*
> @@ -103,17 +104,16 @@ void socrates_fpga_pic_cascade(unsigned int irq, struct irq_desc *desc)
>
> if (cascade_irq != NO_IRQ)
> generic_handle_irq(cascade_irq);
> - desc->chip->eoi(irq);
> -
> + chip->irq_eoi(&desc->irq_data);
> }
>
> -static void socrates_fpga_pic_ack(unsigned int virq)
> +static void socrates_fpga_pic_ack(struct irq_data *d)
> {
> unsigned long flags;
> unsigned int hwirq, irq_line;
> uint32_t mask;
>
> - hwirq = socrates_fpga_irq_to_hw(virq);
> + hwirq = socrates_fpga_irq_to_hw(d->irq);
>
> irq_line = fpga_irqs[hwirq].irq_line;
> raw_spin_lock_irqsave(&socrates_fpga_pic_lock, flags);
> @@ -124,14 +124,14 @@ static void socrates_fpga_pic_ack(unsigned int virq)
> raw_spin_unlock_irqrestore(&socrates_fpga_pic_lock, flags);
> }
>
> -static void socrates_fpga_pic_mask(unsigned int virq)
> +static void socrates_fpga_pic_mask(struct irq_data *d)
> {
> unsigned long flags;
> unsigned int hwirq;
> int irq_line;
> u32 mask;
>
> - hwirq = socrates_fpga_irq_to_hw(virq);
> + hwirq = socrates_fpga_irq_to_hw(d->irq);
>
> irq_line = fpga_irqs[hwirq].irq_line;
> raw_spin_lock_irqsave(&socrates_fpga_pic_lock, flags);
> @@ -142,14 +142,14 @@ static void socrates_fpga_pic_mask(unsigned int virq)
> raw_spin_unlock_irqrestore(&socrates_fpga_pic_lock, flags);
> }
>
> -static void socrates_fpga_pic_mask_ack(unsigned int virq)
> +static void socrates_fpga_pic_mask_ack(struct irq_data *d)
> {
> unsigned long flags;
> unsigned int hwirq;
> int irq_line;
> u32 mask;
>
> - hwirq = socrates_fpga_irq_to_hw(virq);
> + hwirq = socrates_fpga_irq_to_hw(d->irq);
>
> irq_line = fpga_irqs[hwirq].irq_line;
> raw_spin_lock_irqsave(&socrates_fpga_pic_lock, flags);
> @@ -161,14 +161,14 @@ static void socrates_fpga_pic_mask_ack(unsigned int virq)
> raw_spin_unlock_irqrestore(&socrates_fpga_pic_lock, flags);
> }
>
> -static void socrates_fpga_pic_unmask(unsigned int virq)
> +static void socrates_fpga_pic_unmask(struct irq_data *d)
> {
> unsigned long flags;
> unsigned int hwirq;
> int irq_line;
> u32 mask;
>
> - hwirq = socrates_fpga_irq_to_hw(virq);
> + hwirq = socrates_fpga_irq_to_hw(d->irq);
>
> irq_line = fpga_irqs[hwirq].irq_line;
> raw_spin_lock_irqsave(&socrates_fpga_pic_lock, flags);
> @@ -179,14 +179,14 @@ static void socrates_fpga_pic_unmask(unsigned int virq)
> raw_spin_unlock_irqrestore(&socrates_fpga_pic_lock, flags);
> }
>
> -static void socrates_fpga_pic_eoi(unsigned int virq)
> +static void socrates_fpga_pic_eoi(struct irq_data *d)
> {
> unsigned long flags;
> unsigned int hwirq;
> int irq_line;
> u32 mask;
>
> - hwirq = socrates_fpga_irq_to_hw(virq);
> + hwirq = socrates_fpga_irq_to_hw(d->irq);
>
> irq_line = fpga_irqs[hwirq].irq_line;
> raw_spin_lock_irqsave(&socrates_fpga_pic_lock, flags);
> @@ -197,7 +197,7 @@ static void socrates_fpga_pic_eoi(unsigned int virq)
> raw_spin_unlock_irqrestore(&socrates_fpga_pic_lock, flags);
> }
>
> -static int socrates_fpga_pic_set_type(unsigned int virq,
> +static int socrates_fpga_pic_set_type(struct irq_data *d,
> unsigned int flow_type)
> {
> unsigned long flags;
> @@ -205,7 +205,7 @@ static int socrates_fpga_pic_set_type(unsigned int virq,
> int polarity;
> u32 mask;
>
> - hwirq = socrates_fpga_irq_to_hw(virq);
> + hwirq = socrates_fpga_irq_to_hw(d->irq);
>
> if (fpga_irqs[hwirq].type != IRQ_TYPE_NONE)
> return -EINVAL;
> @@ -233,12 +233,12 @@ static int socrates_fpga_pic_set_type(unsigned int virq,
>
> static struct irq_chip socrates_fpga_pic_chip = {
> .name = "FPGA-PIC",
> - .ack = socrates_fpga_pic_ack,
> - .mask = socrates_fpga_pic_mask,
> - .mask_ack = socrates_fpga_pic_mask_ack,
> - .unmask = socrates_fpga_pic_unmask,
> - .eoi = socrates_fpga_pic_eoi,
> - .set_type = socrates_fpga_pic_set_type,
> + .irq_ack = socrates_fpga_pic_ack,
> + .irq_mask = socrates_fpga_pic_mask,
> + .irq_mask_ack = socrates_fpga_pic_mask_ack,
> + .irq_unmask = socrates_fpga_pic_unmask,
> + .irq_eoi = socrates_fpga_pic_eoi,
> + .irq_set_type = socrates_fpga_pic_set_type,
> };
>
> static int socrates_fpga_pic_host_map(struct irq_host *h, unsigned int virq,
> diff --git a/arch/powerpc/platforms/85xx/stx_gp3.c b/arch/powerpc/platforms/85xx/stx_gp3.c
> index bc33d18..2b62b06 100644
> --- a/arch/powerpc/platforms/85xx/stx_gp3.c
> +++ b/arch/powerpc/platforms/85xx/stx_gp3.c
> @@ -46,12 +46,13 @@
>
> static void cpm2_cascade(unsigned int irq, struct irq_desc *desc)
> {
> + struct irq_chip *chip = get_irq_desc_chip(desc);
> int cascade_irq;
>
> while ((cascade_irq = cpm2_get_irq()) >= 0)
> generic_handle_irq(cascade_irq);
>
> - desc->chip->eoi(irq);
> + chip->irq_eoi(&desc->irq_data);
> }
> #endif /* CONFIG_CPM2 */
>
> diff --git a/arch/powerpc/platforms/85xx/tqm85xx.c b/arch/powerpc/platforms/85xx/tqm85xx.c
> index 5e847d0..2265b68 100644
> --- a/arch/powerpc/platforms/85xx/tqm85xx.c
> +++ b/arch/powerpc/platforms/85xx/tqm85xx.c
> @@ -44,12 +44,13 @@
>
> static void cpm2_cascade(unsigned int irq, struct irq_desc *desc)
> {
> + struct irq_chip *chip = get_irq_desc_chip(desc);
> int cascade_irq;
>
> while ((cascade_irq = cpm2_get_irq()) >= 0)
> generic_handle_irq(cascade_irq);
>
> - desc->chip->eoi(irq);
> + chip->irq_eoi(&desc->irq_data);
> }
> #endif /* CONFIG_CPM2 */
>
> diff --git a/arch/powerpc/platforms/86xx/gef_pic.c b/arch/powerpc/platforms/86xx/gef_pic.c
> index 6df9e25..0adfe3b 100644
> --- a/arch/powerpc/platforms/86xx/gef_pic.c
> +++ b/arch/powerpc/platforms/86xx/gef_pic.c
> @@ -95,6 +95,7 @@ static int gef_pic_cascade_irq;
>
> void gef_pic_cascade(unsigned int irq, struct irq_desc *desc)
> {
> + struct irq_chip *chip = get_irq_desc_chip(desc);
> unsigned int cascade_irq;
>
> /*
> @@ -106,17 +107,16 @@ void gef_pic_cascade(unsigned int irq, struct irq_desc *desc)
> if (cascade_irq != NO_IRQ)
> generic_handle_irq(cascade_irq);
>
> - desc->chip->eoi(irq);
> -
> + chip->irq_eoi(&desc->irq_data);
> }
>
> -static void gef_pic_mask(unsigned int virq)
> +static void gef_pic_mask(struct irq_data *d)
> {
> unsigned long flags;
> unsigned int hwirq;
> u32 mask;
>
> - hwirq = gef_irq_to_hw(virq);
> + hwirq = gef_irq_to_hw(d->irq);
>
> raw_spin_lock_irqsave(&gef_pic_lock, flags);
> mask = in_be32(gef_pic_irq_reg_base + GEF_PIC_INTR_MASK(0));
> @@ -125,21 +125,21 @@ static void gef_pic_mask(unsigned int virq)
> raw_spin_unlock_irqrestore(&gef_pic_lock, flags);
> }
>
> -static void gef_pic_mask_ack(unsigned int virq)
> +static void gef_pic_mask_ack(struct irq_data *d)
> {
> /* Don't think we actually have to do anything to ack an interrupt,
> * we just need to clear down the devices interrupt and it will go away
> */
> - gef_pic_mask(virq);
> + gef_pic_mask(d);
> }
>
> -static void gef_pic_unmask(unsigned int virq)
> +static void gef_pic_unmask(struct irq_data *d)
> {
> unsigned long flags;
> unsigned int hwirq;
> u32 mask;
>
> - hwirq = gef_irq_to_hw(virq);
> + hwirq = gef_irq_to_hw(d->irq);
>
> raw_spin_lock_irqsave(&gef_pic_lock, flags);
> mask = in_be32(gef_pic_irq_reg_base + GEF_PIC_INTR_MASK(0));
> @@ -150,9 +150,9 @@ static void gef_pic_unmask(unsigned int virq)
>
> static struct irq_chip gef_pic_chip = {
> .name = "gefp",
> - .mask = gef_pic_mask,
> - .mask_ack = gef_pic_mask_ack,
> - .unmask = gef_pic_unmask,
> + .irq_mask = gef_pic_mask,
> + .irq_mask_ack = gef_pic_mask_ack,
> + .irq_unmask = gef_pic_unmask,
> };
>
>
> diff --git a/arch/powerpc/platforms/86xx/pic.c b/arch/powerpc/platforms/86xx/pic.c
> index 668275d..cbe3363 100644
> --- a/arch/powerpc/platforms/86xx/pic.c
> +++ b/arch/powerpc/platforms/86xx/pic.c
> @@ -19,10 +19,13 @@
> #ifdef CONFIG_PPC_I8259
> static void mpc86xx_8259_cascade(unsigned int irq, struct irq_desc *desc)
> {
> + struct irq_chip *chip = get_irq_desc_chip(desc);
> unsigned int cascade_irq = i8259_irq();
> +
> if (cascade_irq != NO_IRQ)
> generic_handle_irq(cascade_irq);
> - desc->chip->eoi(irq);
> +
> + chip->irq_eoi(&desc->irq_data);
> }
> #endif /* CONFIG_PPC_I8259 */
>
> diff --git a/arch/powerpc/platforms/8xx/m8xx_setup.c b/arch/powerpc/platforms/8xx/m8xx_setup.c
> index 60168c1..fabb108 100644
> --- a/arch/powerpc/platforms/8xx/m8xx_setup.c
> +++ b/arch/powerpc/platforms/8xx/m8xx_setup.c
> @@ -218,15 +218,20 @@ void mpc8xx_restart(char *cmd)
>
> static void cpm_cascade(unsigned int irq, struct irq_desc *desc)
> {
> + struct irq_chip *chip;
> int cascade_irq;
>
> if ((cascade_irq = cpm_get_irq()) >= 0) {
> struct irq_desc *cdesc = irq_to_desc(cascade_irq);
>
> generic_handle_irq(cascade_irq);
> - cdesc->chip->eoi(cascade_irq);
> +
> + chip = get_irq_desc_chip(cdesc);
> + chip->irq_eoi(&cdesc->irq_data);
> }
> - desc->chip->eoi(irq);
> +
> + chip = get_irq_desc_chip(desc);
> + chip->irq_eoi(&desc->irq_data);
> }
>
> /* Initialize the internal interrupt controllers. The number of
> diff --git a/arch/powerpc/platforms/cell/axon_msi.c b/arch/powerpc/platforms/cell/axon_msi.c
> index e3e379c..c07930f 100644
> --- a/arch/powerpc/platforms/cell/axon_msi.c
> +++ b/arch/powerpc/platforms/cell/axon_msi.c
> @@ -93,6 +93,7 @@ static void msic_dcr_write(struct axon_msic *msic, unsigned int dcr_n, u32 val)
>
> static void axon_msi_cascade(unsigned int irq, struct irq_desc *desc)
> {
> + struct irq_chip *chip = get_irq_desc_chip(desc);
> struct axon_msic *msic = get_irq_data(irq);
> u32 write_offset, msi;
> int idx;
> @@ -145,7 +146,7 @@ static void axon_msi_cascade(unsigned int irq, struct irq_desc *desc)
> msic->read_offset &= MSIC_FIFO_SIZE_MASK;
> }
>
> - desc->chip->eoi(irq);
> + chip->irq_eoi(&desc->irq_data);
> }
>
> static struct axon_msic *find_msi_translator(struct pci_dev *dev)
> diff --git a/arch/powerpc/platforms/cell/beat_interrupt.c b/arch/powerpc/platforms/cell/beat_interrupt.c
> index 682af97..0b8f7d7 100644
> --- a/arch/powerpc/platforms/cell/beat_interrupt.c
> +++ b/arch/powerpc/platforms/cell/beat_interrupt.c
> @@ -61,59 +61,59 @@ static inline void beatic_update_irq_mask(unsigned int irq_plug)
> panic("Failed to set mask IRQ!");
> }
>
> -static void beatic_mask_irq(unsigned int irq_plug)
> +static void beatic_mask_irq(struct irq_data *d)
> {
> unsigned long flags;
>
> raw_spin_lock_irqsave(&beatic_irq_mask_lock, flags);
> - beatic_irq_mask_enable[irq_plug/64] &= ~(1UL << (63 - (irq_plug%64)));
> - beatic_update_irq_mask(irq_plug);
> + beatic_irq_mask_enable[d->irq/64] &= ~(1UL << (63 - (d->irq%64)));
> + beatic_update_irq_mask(d->irq);
> raw_spin_unlock_irqrestore(&beatic_irq_mask_lock, flags);
> }
>
> -static void beatic_unmask_irq(unsigned int irq_plug)
> +static void beatic_unmask_irq(struct irq_data *d)
> {
> unsigned long flags;
>
> raw_spin_lock_irqsave(&beatic_irq_mask_lock, flags);
> - beatic_irq_mask_enable[irq_plug/64] |= 1UL << (63 - (irq_plug%64));
> - beatic_update_irq_mask(irq_plug);
> + beatic_irq_mask_enable[d->irq/64] |= 1UL << (63 - (d->irq%64));
> + beatic_update_irq_mask(d->irq);
> raw_spin_unlock_irqrestore(&beatic_irq_mask_lock, flags);
> }
>
> -static void beatic_ack_irq(unsigned int irq_plug)
> +static void beatic_ack_irq(struct irq_data *d)
> {
> unsigned long flags;
>
> raw_spin_lock_irqsave(&beatic_irq_mask_lock, flags);
> - beatic_irq_mask_ack[irq_plug/64] &= ~(1UL << (63 - (irq_plug%64)));
> - beatic_update_irq_mask(irq_plug);
> + beatic_irq_mask_ack[d->irq/64] &= ~(1UL << (63 - (d->irq%64)));
> + beatic_update_irq_mask(d->irq);
> raw_spin_unlock_irqrestore(&beatic_irq_mask_lock, flags);
> }
>
> -static void beatic_end_irq(unsigned int irq_plug)
> +static void beatic_end_irq(struct irq_data *d)
> {
> s64 err;
> unsigned long flags;
>
> - err = beat_downcount_of_interrupt(irq_plug);
> + err = beat_downcount_of_interrupt(d->irq);
> if (err != 0) {
> if ((err & 0xFFFFFFFF) != 0xFFFFFFF5) /* -11: wrong state */
> panic("Failed to downcount IRQ! Error = %16llx", err);
>
> - printk(KERN_ERR "IRQ over-downcounted, plug %d\n", irq_plug);
> + printk(KERN_ERR "IRQ over-downcounted, plug %d\n", d->irq);
> }
> raw_spin_lock_irqsave(&beatic_irq_mask_lock, flags);
> - beatic_irq_mask_ack[irq_plug/64] |= 1UL << (63 - (irq_plug%64));
> - beatic_update_irq_mask(irq_plug);
> + beatic_irq_mask_ack[d->irq/64] |= 1UL << (63 - (d->irq%64));
> + beatic_update_irq_mask(d->irq);
> raw_spin_unlock_irqrestore(&beatic_irq_mask_lock, flags);
> }
>
> static struct irq_chip beatic_pic = {
> .name = "CELL-BEAT",
> - .unmask = beatic_unmask_irq,
> - .mask = beatic_mask_irq,
> - .eoi = beatic_end_irq,
> + .irq_unmask = beatic_unmask_irq,
> + .irq_mask = beatic_mask_irq,
> + .irq_eoi = beatic_end_irq,
> };
>
> /*
> @@ -232,7 +232,7 @@ unsigned int beatic_get_irq(void)
>
> ret = beatic_get_irq_plug();
> if (ret != NO_IRQ)
> - beatic_ack_irq(ret);
> + beatic_ack_irq(irq_get_irq_data(ret));
> return ret;
> }
>
> diff --git a/arch/powerpc/platforms/cell/interrupt.c b/arch/powerpc/platforms/cell/interrupt.c
> index 10eb1a4..624d26e 100644
> --- a/arch/powerpc/platforms/cell/interrupt.c
> +++ b/arch/powerpc/platforms/cell/interrupt.c
> @@ -72,15 +72,15 @@ static irq_hw_number_t iic_pending_to_hwnum(struct cbe_iic_pending_bits bits)
> return (node << IIC_IRQ_NODE_SHIFT) | (class << 4) | unit;
> }
>
> -static void iic_mask(unsigned int irq)
> +static void iic_mask(struct irq_data *d)
> {
> }
>
> -static void iic_unmask(unsigned int irq)
> +static void iic_unmask(struct irq_data *d)
> {
> }
>
> -static void iic_eoi(unsigned int irq)
> +static void iic_eoi(struct irq_data *d)
> {
> struct iic *iic = &__get_cpu_var(cpu_iic);
> out_be64(&iic->regs->prio, iic->eoi_stack[--iic->eoi_ptr]);
> @@ -89,19 +89,21 @@ static void iic_eoi(unsigned int irq)
>
> static struct irq_chip iic_chip = {
> .name = "CELL-IIC",
> - .mask = iic_mask,
> - .unmask = iic_unmask,
> - .eoi = iic_eoi,
> + .irq_mask = iic_mask,
> + .irq_unmask = iic_unmask,
> + .irq_eoi = iic_eoi,
> };
>
>
> -static void iic_ioexc_eoi(unsigned int irq)
> +static void iic_ioexc_eoi(struct irq_data *d)
> {
> }
>
> static void iic_ioexc_cascade(unsigned int irq, struct irq_desc *desc)
> {
> - struct cbe_iic_regs __iomem *node_iic = (void __iomem *)desc->handler_data;
> + struct irq_chip *chip = get_irq_desc_chip(desc);
> + struct cbe_iic_regs __iomem *node_iic =
> + (void __iomem *)get_irq_desc_data(desc);
> unsigned int base = (irq & 0xffffff00) | IIC_IRQ_TYPE_IOEXC;
> unsigned long bits, ack;
> int cascade;
> @@ -128,15 +130,15 @@ static void iic_ioexc_cascade(unsigned int irq, struct irq_desc *desc)
> if (ack)
> out_be64(&node_iic->iic_is, ack);
> }
> - desc->chip->eoi(irq);
> + chip->irq_eoi(&desc->irq_data);
> }
>
>
> static struct irq_chip iic_ioexc_chip = {
> .name = "CELL-IOEX",
> - .mask = iic_mask,
> - .unmask = iic_unmask,
> - .eoi = iic_ioexc_eoi,
> + .irq_mask = iic_mask,
> + .irq_unmask = iic_unmask,
> + .irq_eoi = iic_ioexc_eoi,
> };
>
> /* Get an IRQ number from the pending state register of the IIC */
> @@ -237,6 +239,8 @@ extern int noirqdebug;
>
> static void handle_iic_irq(unsigned int irq, struct irq_desc *desc)
> {
> + struct irq_chip *chip = get_irq_desc_chip(desc);
> +
> raw_spin_lock(&desc->lock);
>
> desc->status &= ~(IRQ_REPLAY | IRQ_WAITING);
> @@ -275,7 +279,7 @@ static void handle_iic_irq(unsigned int irq, struct irq_desc *desc)
>
> desc->status &= ~IRQ_INPROGRESS;
> out_eoi:
> - desc->chip->eoi(irq);
> + chip->irq_eoi(&desc->irq_data);
> raw_spin_unlock(&desc->lock);
> }
>
> diff --git a/arch/powerpc/platforms/cell/setup.c b/arch/powerpc/platforms/cell/setup.c
> index 6919957..6a28d02 100644
> --- a/arch/powerpc/platforms/cell/setup.c
> +++ b/arch/powerpc/platforms/cell/setup.c
> @@ -187,13 +187,15 @@ machine_subsys_initcall(cell, cell_publish_devices);
>
> static void cell_mpic_cascade(unsigned int irq, struct irq_desc *desc)
> {
> - struct mpic *mpic = desc->handler_data;
> + struct irq_chip *chip = get_irq_desc_chip(desc);
> + struct mpic *mpic = get_irq_desc_data(desc);
> unsigned int virq;
>
> virq = mpic_get_one_irq(mpic);
> if (virq != NO_IRQ)
> generic_handle_irq(virq);
> - desc->chip->eoi(irq);
> +
> + chip->irq_eoi(&desc->irq_data);
> }
>
> static void __init mpic_init_IRQ(void)
> diff --git a/arch/powerpc/platforms/cell/spider-pic.c b/arch/powerpc/platforms/cell/spider-pic.c
> index 3f2e557..b38cdfc 100644
> --- a/arch/powerpc/platforms/cell/spider-pic.c
> +++ b/arch/powerpc/platforms/cell/spider-pic.c
> @@ -79,30 +79,30 @@ static void __iomem *spider_get_irq_config(struct spider_pic *pic,
> return pic->regs + TIR_CFGA + 8 * src;
> }
>
> -static void spider_unmask_irq(unsigned int virq)
> +static void spider_unmask_irq(struct irq_data *d)
> {
> - struct spider_pic *pic = spider_virq_to_pic(virq);
> - void __iomem *cfg = spider_get_irq_config(pic, irq_map[virq].hwirq);
> + struct spider_pic *pic = spider_virq_to_pic(d->irq);
> + void __iomem *cfg = spider_get_irq_config(pic, irq_map[d->irq].hwirq);
>
> out_be32(cfg, in_be32(cfg) | 0x30000000u);
> }
>
> -static void spider_mask_irq(unsigned int virq)
> +static void spider_mask_irq(struct irq_data *d)
> {
> - struct spider_pic *pic = spider_virq_to_pic(virq);
> - void __iomem *cfg = spider_get_irq_config(pic, irq_map[virq].hwirq);
> + struct spider_pic *pic = spider_virq_to_pic(d->irq);
> + void __iomem *cfg = spider_get_irq_config(pic, irq_map[d->irq].hwirq);
>
> out_be32(cfg, in_be32(cfg) & ~0x30000000u);
> }
>
> -static void spider_ack_irq(unsigned int virq)
> +static void spider_ack_irq(struct irq_data *d)
> {
> - struct spider_pic *pic = spider_virq_to_pic(virq);
> - unsigned int src = irq_map[virq].hwirq;
> + struct spider_pic *pic = spider_virq_to_pic(d->irq);
> + unsigned int src = irq_map[d->irq].hwirq;
>
> /* Reset edge detection logic if necessary
> */
> - if (irq_to_desc(virq)->status & IRQ_LEVEL)
> + if (irq_to_desc(d->irq)->status & IRQ_LEVEL)
> return;
>
> /* Only interrupts 47 to 50 can be set to edge */
> @@ -113,13 +113,13 @@ static void spider_ack_irq(unsigned int virq)
> out_be32(pic->regs + TIR_EDC, 0x100 | (src & 0xf));
> }
>
> -static int spider_set_irq_type(unsigned int virq, unsigned int type)
> +static int spider_set_irq_type(struct irq_data *d, unsigned int type)
> {
> unsigned int sense = type & IRQ_TYPE_SENSE_MASK;
> - struct spider_pic *pic = spider_virq_to_pic(virq);
> - unsigned int hw = irq_map[virq].hwirq;
> + struct spider_pic *pic = spider_virq_to_pic(d->irq);
> + unsigned int hw = irq_map[d->irq].hwirq;
> void __iomem *cfg = spider_get_irq_config(pic, hw);
> - struct irq_desc *desc = irq_to_desc(virq);
> + struct irq_desc *desc = irq_to_desc(d->irq);
> u32 old_mask;
> u32 ic;
>
> @@ -169,10 +169,10 @@ static int spider_set_irq_type(unsigned int virq, unsigned int type)
>
> static struct irq_chip spider_pic = {
> .name = "SPIDER",
> - .unmask = spider_unmask_irq,
> - .mask = spider_mask_irq,
> - .ack = spider_ack_irq,
> - .set_type = spider_set_irq_type,
> + .irq_unmask = spider_unmask_irq,
> + .irq_mask = spider_mask_irq,
> + .irq_ack = spider_ack_irq,
> + .irq_set_type = spider_set_irq_type,
> };
>
> static int spider_host_map(struct irq_host *h, unsigned int virq,
> @@ -207,7 +207,8 @@ static struct irq_host_ops spider_host_ops = {
>
> static void spider_irq_cascade(unsigned int irq, struct irq_desc *desc)
> {
> - struct spider_pic *pic = desc->handler_data;
> + struct irq_chip *chip = get_irq_desc_chip(desc);
> + struct spider_pic *pic = get_irq_desc_data(desc);
> unsigned int cs, virq;
>
> cs = in_be32(pic->regs + TIR_CS) >> 24;
> @@ -215,9 +216,11 @@ static void spider_irq_cascade(unsigned int irq, struct irq_desc *desc)
> virq = NO_IRQ;
> else
> virq = irq_linear_revmap(pic->host, cs);
> +
> if (virq != NO_IRQ)
> generic_handle_irq(virq);
> - desc->chip->eoi(irq);
> +
> + chip->irq_eoi(&desc->irq_data);
> }
>
> /* For hooking up the cascace we have a problem. Our device-tree is
> diff --git a/arch/powerpc/platforms/chrp/setup.c b/arch/powerpc/platforms/chrp/setup.c
> index 8553cc4..4c12884 100644
> --- a/arch/powerpc/platforms/chrp/setup.c
> +++ b/arch/powerpc/platforms/chrp/setup.c
> @@ -365,10 +365,13 @@ void __init chrp_setup_arch(void)
>
> static void chrp_8259_cascade(unsigned int irq, struct irq_desc *desc)
> {
> + struct irq_chip *chip = get_irq_desc_chip(desc);
> unsigned int cascade_irq = i8259_irq();
> +
> if (cascade_irq != NO_IRQ)
> generic_handle_irq(cascade_irq);
> - desc->chip->eoi(irq);
> +
> + chip->irq_eoi(&desc->irq_data);
> }
>
> /*
> diff --git a/arch/powerpc/platforms/embedded6xx/flipper-pic.c b/arch/powerpc/platforms/embedded6xx/flipper-pic.c
> index c278bd3..d7287e8 100644
> --- a/arch/powerpc/platforms/embedded6xx/flipper-pic.c
> +++ b/arch/powerpc/platforms/embedded6xx/flipper-pic.c
> @@ -46,10 +46,10 @@
> *
> */
>
> -static void flipper_pic_mask_and_ack(unsigned int virq)
> +static void flipper_pic_mask_and_ack(struct irq_data *d)
> {
> - int irq = virq_to_hw(virq);
> - void __iomem *io_base = get_irq_chip_data(virq);
> + int irq = virq_to_hw(d->irq);
> + void __iomem *io_base = get_irq_chip_data(d->irq);
> u32 mask = 1 << irq;
>
> clrbits32(io_base + FLIPPER_IMR, mask);
> @@ -57,27 +57,27 @@ static void flipper_pic_mask_and_ack(unsigned int virq)
> out_be32(io_base + FLIPPER_ICR, mask);
> }
>
> -static void flipper_pic_ack(unsigned int virq)
> +static void flipper_pic_ack(struct irq_data *d)
> {
> - int irq = virq_to_hw(virq);
> - void __iomem *io_base = get_irq_chip_data(virq);
> + int irq = virq_to_hw(d->irq);
> + void __iomem *io_base = get_irq_chip_data(d->irq);
>
> /* this is at least needed for RSW */
> out_be32(io_base + FLIPPER_ICR, 1 << irq);
> }
>
> -static void flipper_pic_mask(unsigned int virq)
> +static void flipper_pic_mask(struct irq_data *d)
> {
> - int irq = virq_to_hw(virq);
> - void __iomem *io_base = get_irq_chip_data(virq);
> + int irq = virq_to_hw(d->irq);
> + void __iomem *io_base = get_irq_chip_data(d->irq);
>
> clrbits32(io_base + FLIPPER_IMR, 1 << irq);
> }
>
> -static void flipper_pic_unmask(unsigned int virq)
> +static void flipper_pic_unmask(struct irq_data *d)
> {
> - int irq = virq_to_hw(virq);
> - void __iomem *io_base = get_irq_chip_data(virq);
> + int irq = virq_to_hw(d->irq);
> + void __iomem *io_base = get_irq_chip_data(d->irq);
>
> setbits32(io_base + FLIPPER_IMR, 1 << irq);
> }
> @@ -85,10 +85,10 @@ static void flipper_pic_unmask(unsigned int virq)
>
> static struct irq_chip flipper_pic = {
> .name = "flipper-pic",
> - .ack = flipper_pic_ack,
> - .mask_ack = flipper_pic_mask_and_ack,
> - .mask = flipper_pic_mask,
> - .unmask = flipper_pic_unmask,
> + .irq_ack = flipper_pic_ack,
> + .irq_mask_ack = flipper_pic_mask_and_ack,
> + .irq_mask = flipper_pic_mask,
> + .irq_unmask = flipper_pic_unmask,
> };
>
> /*
> diff --git a/arch/powerpc/platforms/embedded6xx/hlwd-pic.c b/arch/powerpc/platforms/embedded6xx/hlwd-pic.c
> index a771f91..c6f5fd6 100644
> --- a/arch/powerpc/platforms/embedded6xx/hlwd-pic.c
> +++ b/arch/powerpc/platforms/embedded6xx/hlwd-pic.c
> @@ -41,36 +41,36 @@
> *
> */
>
> -static void hlwd_pic_mask_and_ack(unsigned int virq)
> +static void hlwd_pic_mask_and_ack(struct irq_data *d)
> {
> - int irq = virq_to_hw(virq);
> - void __iomem *io_base = get_irq_chip_data(virq);
> + int irq = virq_to_hw(d->irq);
> + void __iomem *io_base = get_irq_chip_data(d->irq);
> u32 mask = 1 << irq;
>
> clrbits32(io_base + HW_BROADWAY_IMR, mask);
> out_be32(io_base + HW_BROADWAY_ICR, mask);
> }
>
> -static void hlwd_pic_ack(unsigned int virq)
> +static void hlwd_pic_ack(struct irq_data *d)
> {
> - int irq = virq_to_hw(virq);
> - void __iomem *io_base = get_irq_chip_data(virq);
> + int irq = virq_to_hw(d->irq);
> + void __iomem *io_base = get_irq_chip_data(d->irq);
>
> out_be32(io_base + HW_BROADWAY_ICR, 1 << irq);
> }
>
> -static void hlwd_pic_mask(unsigned int virq)
> +static void hlwd_pic_mask(struct irq_data *d)
> {
> - int irq = virq_to_hw(virq);
> - void __iomem *io_base = get_irq_chip_data(virq);
> + int irq = virq_to_hw(d->irq);
> + void __iomem *io_base = get_irq_chip_data(d->irq);
>
> clrbits32(io_base + HW_BROADWAY_IMR, 1 << irq);
> }
>
> -static void hlwd_pic_unmask(unsigned int virq)
> +static void hlwd_pic_unmask(struct irq_data *d)
> {
> - int irq = virq_to_hw(virq);
> - void __iomem *io_base = get_irq_chip_data(virq);
> + int irq = virq_to_hw(d->irq);
> + void __iomem *io_base = get_irq_chip_data(d->irq);
>
> setbits32(io_base + HW_BROADWAY_IMR, 1 << irq);
> }
> @@ -78,10 +78,10 @@ static void hlwd_pic_unmask(unsigned int virq)
>
> static struct irq_chip hlwd_pic = {
> .name = "hlwd-pic",
> - .ack = hlwd_pic_ack,
> - .mask_ack = hlwd_pic_mask_and_ack,
> - .mask = hlwd_pic_mask,
> - .unmask = hlwd_pic_unmask,
> + .irq_ack = hlwd_pic_ack,
> + .irq_mask_ack = hlwd_pic_mask_and_ack,
> + .irq_mask = hlwd_pic_mask,
> + .irq_unmask = hlwd_pic_unmask,
> };
>
> /*
> @@ -129,11 +129,12 @@ static unsigned int __hlwd_pic_get_irq(struct irq_host *h)
> static void hlwd_pic_irq_cascade(unsigned int cascade_virq,
> struct irq_desc *desc)
> {
> + struct irq_chip *chip = get_irq_desc_chip(desc);
> struct irq_host *irq_host = get_irq_data(cascade_virq);
> unsigned int virq;
>
> raw_spin_lock(&desc->lock);
> - desc->chip->mask(cascade_virq); /* IRQ_LEVEL */
> + chip->irq_mask(&desc->irq_data); /* IRQ_LEVEL */
> raw_spin_unlock(&desc->lock);
>
> virq = __hlwd_pic_get_irq(irq_host);
> @@ -143,9 +144,9 @@ static void hlwd_pic_irq_cascade(unsigned int cascade_virq,
> pr_err("spurious interrupt!\n");
>
> raw_spin_lock(&desc->lock);
> - desc->chip->ack(cascade_virq); /* IRQ_LEVEL */
> - if (!(desc->status & IRQ_DISABLED) && desc->chip->unmask)
> - desc->chip->unmask(cascade_virq);
> + chip->irq_ack(&desc->irq_data); /* IRQ_LEVEL */
> + if (!(desc->status & IRQ_DISABLED) && chip->irq_unmask)
> + chip->irq_unmask(&desc->irq_data);
> raw_spin_unlock(&desc->lock);
> }
>
> diff --git a/arch/powerpc/platforms/iseries/irq.c b/arch/powerpc/platforms/iseries/irq.c
> index ba446bf..4fb96f0 100644
> --- a/arch/powerpc/platforms/iseries/irq.c
> +++ b/arch/powerpc/platforms/iseries/irq.c
> @@ -167,11 +167,11 @@ static void pci_event_handler(struct HvLpEvent *event)
> * This will be called by device drivers (via enable_IRQ)
> * to enable INTA in the bridge interrupt status register.
> */
> -static void iseries_enable_IRQ(unsigned int irq)
> +static void iseries_enable_IRQ(struct irq_data *d)
> {
> u32 bus, dev_id, function, mask;
> const u32 sub_bus = 0;
> - unsigned int rirq = (unsigned int)irq_map[irq].hwirq;
> + unsigned int rirq = (unsigned int)irq_map[d->irq].hwirq;
>
> /* The IRQ has already been locked by the caller */
> bus = REAL_IRQ_TO_BUS(rirq);
> @@ -184,23 +184,23 @@ static void iseries_enable_IRQ(unsigned int irq)
> }
>
> /* This is called by iseries_activate_IRQs */
> -static unsigned int iseries_startup_IRQ(unsigned int irq)
> +static unsigned int iseries_startup_IRQ(struct irq_data *d)
> {
> u32 bus, dev_id, function, mask;
> const u32 sub_bus = 0;
> - unsigned int rirq = (unsigned int)irq_map[irq].hwirq;
> + unsigned int rirq = (unsigned int)irq_map[d->irq].hwirq;
>
> bus = REAL_IRQ_TO_BUS(rirq);
> function = REAL_IRQ_TO_FUNC(rirq);
> dev_id = (REAL_IRQ_TO_IDSEL(rirq) << 4) + function;
>
> /* Link the IRQ number to the bridge */
> - HvCallXm_connectBusUnit(bus, sub_bus, dev_id, irq);
> + HvCallXm_connectBusUnit(bus, sub_bus, dev_id, d->irq);
>
> /* Unmask bridge interrupts in the FISR */
> mask = 0x01010000 << function;
> HvCallPci_unmaskFisr(bus, sub_bus, dev_id, mask);
> - iseries_enable_IRQ(irq);
> + iseries_enable_IRQ(d);
> return 0;
> }
>
> @@ -215,21 +215,26 @@ void __init iSeries_activate_IRQs()
>
> for_each_irq (irq) {
> struct irq_desc *desc = irq_to_desc(irq);
> + struct irq_chip *chip;
>
> - if (desc && desc->chip && desc->chip->startup) {
> + if (!desc)
> + continue;
> +
> + chip = get_irq_desc_chip(desc);
> + if (chip && chip->irq_startup) {
> raw_spin_lock_irqsave(&desc->lock, flags);
> - desc->chip->startup(irq);
> + chip->irq_startup(&desc->irq_data);
> raw_spin_unlock_irqrestore(&desc->lock, flags);
> }
> }
> }
>
> /* this is not called anywhere currently */
> -static void iseries_shutdown_IRQ(unsigned int irq)
> +static void iseries_shutdown_IRQ(struct irq_data *d)
> {
> u32 bus, dev_id, function, mask;
> const u32 sub_bus = 0;
> - unsigned int rirq = (unsigned int)irq_map[irq].hwirq;
> + unsigned int rirq = (unsigned int)irq_map[d->irq].hwirq;
>
> /* irq should be locked by the caller */
> bus = REAL_IRQ_TO_BUS(rirq);
> @@ -248,11 +253,11 @@ static void iseries_shutdown_IRQ(unsigned int irq)
> * This will be called by device drivers (via disable_IRQ)
> * to disable INTA in the bridge interrupt status register.
> */
> -static void iseries_disable_IRQ(unsigned int irq)
> +static void iseries_disable_IRQ(struct irq_data *d)
> {
> u32 bus, dev_id, function, mask;
> const u32 sub_bus = 0;
> - unsigned int rirq = (unsigned int)irq_map[irq].hwirq;
> + unsigned int rirq = (unsigned int)irq_map[d->irq].hwirq;
>
> /* The IRQ has already been locked by the caller */
> bus = REAL_IRQ_TO_BUS(rirq);
> @@ -264,9 +269,9 @@ static void iseries_disable_IRQ(unsigned int irq)
> HvCallPci_maskInterrupts(bus, sub_bus, dev_id, mask);
> }
>
> -static void iseries_end_IRQ(unsigned int irq)
> +static void iseries_end_IRQ(struct irq_data *d)
> {
> - unsigned int rirq = (unsigned int)irq_map[irq].hwirq;
> + unsigned int rirq = (unsigned int)irq_map[d->irq].hwirq;
>
> HvCallPci_eoi(REAL_IRQ_TO_BUS(rirq), REAL_IRQ_TO_SUBBUS(rirq),
> (REAL_IRQ_TO_IDSEL(rirq) << 4) + REAL_IRQ_TO_FUNC(rirq));
> @@ -274,11 +279,11 @@ static void iseries_end_IRQ(unsigned int irq)
>
> static struct irq_chip iseries_pic = {
> .name = "iSeries",
> - .startup = iseries_startup_IRQ,
> - .shutdown = iseries_shutdown_IRQ,
> - .unmask = iseries_enable_IRQ,
> - .mask = iseries_disable_IRQ,
> - .eoi = iseries_end_IRQ
> + .irq_startup = iseries_startup_IRQ,
> + .irq_shutdown = iseries_shutdown_IRQ,
> + .irq_unmask = iseries_enable_IRQ,
> + .irq_mask = iseries_disable_IRQ,
> + .irq_eoi = iseries_end_IRQ
> };
>
> /*
> diff --git a/arch/powerpc/platforms/powermac/pic.c b/arch/powerpc/platforms/powermac/pic.c
> index 890d5f7..c55812b 100644
> --- a/arch/powerpc/platforms/powermac/pic.c
> +++ b/arch/powerpc/platforms/powermac/pic.c
> @@ -82,9 +82,9 @@ static void __pmac_retrigger(unsigned int irq_nr)
> }
> }
>
> -static void pmac_mask_and_ack_irq(unsigned int virq)
> +static void pmac_mask_and_ack_irq(struct irq_data *d)
> {
> - unsigned int src = irq_map[virq].hwirq;
> + unsigned int src = irq_map[d->irq].hwirq;
> unsigned long bit = 1UL << (src & 0x1f);
> int i = src >> 5;
> unsigned long flags;
> @@ -104,9 +104,9 @@ static void pmac_mask_and_ack_irq(unsigned int virq)
> raw_spin_unlock_irqrestore(&pmac_pic_lock, flags);
> }
>
> -static void pmac_ack_irq(unsigned int virq)
> +static void pmac_ack_irq(struct irq_data *d)
> {
> - unsigned int src = irq_map[virq].hwirq;
> + unsigned int src = irq_map[d->irq].hwirq;
> unsigned long bit = 1UL << (src & 0x1f);
> int i = src >> 5;
> unsigned long flags;
> @@ -149,15 +149,15 @@ static void __pmac_set_irq_mask(unsigned int irq_nr, int nokicklost)
> /* When an irq gets requested for the first client, if it's an
> * edge interrupt, we clear any previous one on the controller
> */
> -static unsigned int pmac_startup_irq(unsigned int virq)
> +static unsigned int pmac_startup_irq(struct irq_data *d)
> {
> unsigned long flags;
> - unsigned int src = irq_map[virq].hwirq;
> + unsigned int src = irq_map[d->irq].hwirq;
> unsigned long bit = 1UL << (src & 0x1f);
> int i = src >> 5;
>
> raw_spin_lock_irqsave(&pmac_pic_lock, flags);
> - if ((irq_to_desc(virq)->status & IRQ_LEVEL) == 0)
> + if ((irq_to_desc(d->irq)->status & IRQ_LEVEL) == 0)
> out_le32(&pmac_irq_hw[i]->ack, bit);
> __set_bit(src, ppc_cached_irq_mask);
> __pmac_set_irq_mask(src, 0);
> @@ -166,10 +166,10 @@ static unsigned int pmac_startup_irq(unsigned int virq)
> return 0;
> }
>
> -static void pmac_mask_irq(unsigned int virq)
> +static void pmac_mask_irq(struct irq_data *d)
> {
> unsigned long flags;
> - unsigned int src = irq_map[virq].hwirq;
> + unsigned int src = irq_map[d->irq].hwirq;
>
> raw_spin_lock_irqsave(&pmac_pic_lock, flags);
> __clear_bit(src, ppc_cached_irq_mask);
> @@ -177,10 +177,10 @@ static void pmac_mask_irq(unsigned int virq)
> raw_spin_unlock_irqrestore(&pmac_pic_lock, flags);
> }
>
> -static void pmac_unmask_irq(unsigned int virq)
> +static void pmac_unmask_irq(struct irq_data *d)
> {
> unsigned long flags;
> - unsigned int src = irq_map[virq].hwirq;
> + unsigned int src = irq_map[d->irq].hwirq;
>
> raw_spin_lock_irqsave(&pmac_pic_lock, flags);
> __set_bit(src, ppc_cached_irq_mask);
> @@ -188,24 +188,24 @@ static void pmac_unmask_irq(unsigned int virq)
> raw_spin_unlock_irqrestore(&pmac_pic_lock, flags);
> }
>
> -static int pmac_retrigger(unsigned int virq)
> +static int pmac_retrigger(struct irq_data *d)
> {
> unsigned long flags;
>
> raw_spin_lock_irqsave(&pmac_pic_lock, flags);
> - __pmac_retrigger(irq_map[virq].hwirq);
> + __pmac_retrigger(irq_map[d->irq].hwirq);
> raw_spin_unlock_irqrestore(&pmac_pic_lock, flags);
> return 1;
> }
>
> static struct irq_chip pmac_pic = {
> .name = "PMAC-PIC",
> - .startup = pmac_startup_irq,
> - .mask = pmac_mask_irq,
> - .ack = pmac_ack_irq,
> - .mask_ack = pmac_mask_and_ack_irq,
> - .unmask = pmac_unmask_irq,
> - .retrigger = pmac_retrigger,
> + .irq_startup = pmac_startup_irq,
> + .irq_mask = pmac_mask_irq,
> + .irq_ack = pmac_ack_irq,
> + .irq_mask_ack = pmac_mask_and_ack_irq,
> + .irq_unmask = pmac_unmask_irq,
> + .irq_retrigger = pmac_retrigger,
> };
>
> static irqreturn_t gatwick_action(int cpl, void *dev_id)
> @@ -472,12 +472,14 @@ int of_irq_map_oldworld(struct device_node *device, int index,
>
> static void pmac_u3_cascade(unsigned int irq, struct irq_desc *desc)
> {
> - struct mpic *mpic = desc->handler_data;
> -
> + struct irq_chip *chip = get_irq_desc_chip(desc);
> + struct mpic *mpic = get_irq_desc_data(desc);
> unsigned int cascade_irq = mpic_get_one_irq(mpic);
> +
> if (cascade_irq != NO_IRQ)
> generic_handle_irq(cascade_irq);
> - desc->chip->eoi(irq);
> +
> + chip->irq_eoi(&desc->irq_data);
> }
>
> static void __init pmac_pic_setup_mpic_nmi(struct mpic *mpic)
> @@ -707,7 +709,7 @@ static int pmacpic_resume(struct sys_device *sysdev)
> mb();
> for (i = 0; i < max_real_irqs; ++i)
> if (test_bit(i, sleep_save_mask))
> - pmac_unmask_irq(i);
> + pmac_unmask_irq(irq_get_irq_data(i));
>
> return 0;
> }
> diff --git a/arch/powerpc/platforms/ps3/interrupt.c b/arch/powerpc/platforms/ps3/interrupt.c
> index 92290ff..4b3cc34 100644
> --- a/arch/powerpc/platforms/ps3/interrupt.c
> +++ b/arch/powerpc/platforms/ps3/interrupt.c
> @@ -99,16 +99,16 @@ static DEFINE_PER_CPU(struct ps3_private, ps3_private);
> * Sets ps3_bmp.mask and calls lv1_did_update_interrupt_mask().
> */
>
> -static void ps3_chip_mask(unsigned int virq)
> +static void ps3_chip_mask(struct irq_data *d)
> {
> - struct ps3_private *pd = get_irq_chip_data(virq);
> + struct ps3_private *pd = get_irq_chip_data(d->irq);
> unsigned long flags;
>
> pr_debug("%s:%d: thread_id %llu, virq %d\n", __func__, __LINE__,
> - pd->thread_id, virq);
> + pd->thread_id, d->irq);
>
> local_irq_save(flags);
> - clear_bit(63 - virq, &pd->bmp.mask);
> + clear_bit(63 - d->irq, &pd->bmp.mask);
> lv1_did_update_interrupt_mask(pd->ppe_id, pd->thread_id);
> local_irq_restore(flags);
> }
> @@ -120,16 +120,16 @@ static void ps3_chip_mask(unsigned int virq)
> * Clears ps3_bmp.mask and calls lv1_did_update_interrupt_mask().
> */
>
> -static void ps3_chip_unmask(unsigned int virq)
> +static void ps3_chip_unmask(struct irq_data *d)
> {
> - struct ps3_private *pd = get_irq_chip_data(virq);
> + struct ps3_private *pd = get_irq_chip_data(d->irq);
> unsigned long flags;
>
> pr_debug("%s:%d: thread_id %llu, virq %d\n", __func__, __LINE__,
> - pd->thread_id, virq);
> + pd->thread_id, d->irq);
>
> local_irq_save(flags);
> - set_bit(63 - virq, &pd->bmp.mask);
> + set_bit(63 - d->irq, &pd->bmp.mask);
> lv1_did_update_interrupt_mask(pd->ppe_id, pd->thread_id);
> local_irq_restore(flags);
> }
> @@ -141,10 +141,10 @@ static void ps3_chip_unmask(unsigned int virq)
> * Calls lv1_end_of_interrupt_ext().
> */
>
> -static void ps3_chip_eoi(unsigned int virq)
> +static void ps3_chip_eoi(struct irq_data *d)
> {
> - const struct ps3_private *pd = get_irq_chip_data(virq);
> - lv1_end_of_interrupt_ext(pd->ppe_id, pd->thread_id, virq);
> + const struct ps3_private *pd = get_irq_chip_data(d->irq);
> + lv1_end_of_interrupt_ext(pd->ppe_id, pd->thread_id, d->irq);
> }
>
> /**
> @@ -153,9 +153,9 @@ static void ps3_chip_eoi(unsigned int virq)
>
> static struct irq_chip ps3_irq_chip = {
> .name = "ps3",
> - .mask = ps3_chip_mask,
> - .unmask = ps3_chip_unmask,
> - .eoi = ps3_chip_eoi,
> + .irq_mask = ps3_chip_mask,
> + .irq_unmask = ps3_chip_unmask,
> + .irq_eoi = ps3_chip_eoi,
> };
>
> /**
> diff --git a/arch/powerpc/platforms/pseries/setup.c b/arch/powerpc/platforms/pseries/setup.c
> index d345bfd..2a0089a 100644
> --- a/arch/powerpc/platforms/pseries/setup.c
> +++ b/arch/powerpc/platforms/pseries/setup.c
> @@ -114,10 +114,13 @@ static void __init fwnmi_init(void)
>
> static void pseries_8259_cascade(unsigned int irq, struct irq_desc *desc)
> {
> + struct irq_chip *chip = get_irq_desc_chip(desc);
> unsigned int cascade_irq = i8259_irq();
> +
> if (cascade_irq != NO_IRQ)
> generic_handle_irq(cascade_irq);
> - desc->chip->eoi(irq);
> +
> + chip->irq_eoi(&desc->irq_data);
> }
>
> static void __init pseries_setup_i8259_cascade(void)
> diff --git a/arch/powerpc/platforms/pseries/xics.c b/arch/powerpc/platforms/pseries/xics.c
> index 7b96e5a..7e8ad8e 100644
> --- a/arch/powerpc/platforms/pseries/xics.c
> +++ b/arch/powerpc/platforms/pseries/xics.c
> @@ -202,20 +202,20 @@ static int get_irq_server(unsigned int virq, const struct cpumask *cpumask,
> #define get_irq_server(virq, cpumask, strict_check) (default_server)
> #endif
>
> -static void xics_unmask_irq(unsigned int virq)
> +static void xics_unmask_irq(struct irq_data *d)
> {
> unsigned int irq;
> int call_status;
> int server;
>
> - pr_devel("xics: unmask virq %d\n", virq);
> + pr_devel("xics: unmask virq %d\n", d->irq);
>
> - irq = (unsigned int)irq_map[virq].hwirq;
> + irq = (unsigned int)irq_map[d->irq].hwirq;
> pr_devel(" -> map to hwirq 0x%x\n", irq);
> if (irq == XICS_IPI || irq == XICS_IRQ_SPURIOUS)
> return;
>
> - server = get_irq_server(virq, irq_to_desc(virq)->affinity, 0);
> + server = get_irq_server(d->irq, irq_to_desc(d->irq)->affinity, 0);
>
> call_status = rtas_call(ibm_set_xive, 3, 1, NULL, irq, server,
> DEFAULT_PRIORITY);
> @@ -235,22 +235,22 @@ static void xics_unmask_irq(unsigned int virq)
> }
> }
>
> -static unsigned int xics_startup(unsigned int virq)
> +static unsigned int xics_startup(struct irq_data *d)
> {
> /*
> * The generic MSI code returns with the interrupt disabled on the
> * card, using the MSI mask bits. Firmware doesn't appear to unmask
> * at that level, so we do it here by hand.
> */
> - if (irq_to_desc(virq)->msi_desc)
> - unmask_msi_irq(irq_get_irq_data(virq));
> + if (irq_to_desc(d->irq)->msi_desc)
> + unmask_msi_irq(d);
>
> /* unmask it */
> - xics_unmask_irq(virq);
> + xics_unmask_irq(d);
> return 0;
> }
>
> -static void xics_mask_real_irq(unsigned int irq)
> +static void xics_mask_real_irq(struct irq_data *d)
> {
> int call_status;
>
> @@ -274,13 +274,13 @@ static void xics_mask_real_irq(unsigned int irq)
> }
> }
>
> -static void xics_mask_irq(unsigned int virq)
> +static void xics_mask_irq(struct irq_data *d)
> {
> unsigned int irq;
>
> - pr_devel("xics: mask virq %d\n", virq);
> + pr_devel("xics: mask virq %d\n", d->irq);
>
> - irq = (unsigned int)irq_map[virq].hwirq;
> + irq = (unsigned int)irq_map[d->irq].hwirq;
> if (irq == XICS_IPI || irq == XICS_IRQ_SPURIOUS)
> return;
> xics_mask_real_irq(irq);
> @@ -371,30 +371,31 @@ static unsigned char pop_cppr(void)
> return os_cppr->stack[--os_cppr->index];
> }
>
> -static void xics_eoi_direct(unsigned int virq)
> +static void xics_eoi_direct(struct irq_data *d)
> {
> - unsigned int irq = (unsigned int)irq_map[virq].hwirq;
> + unsigned int irq = (unsigned int)irq_map[d->irq].hwirq;
>
> iosync();
> direct_xirr_info_set((pop_cppr() << 24) | irq);
> }
>
> -static void xics_eoi_lpar(unsigned int virq)
> +static void xics_eoi_lpar(struct irq_data *d)
> {
> - unsigned int irq = (unsigned int)irq_map[virq].hwirq;
> + unsigned int irq = (unsigned int)irq_map[d->irq].hwirq;
>
> iosync();
> lpar_xirr_info_set((pop_cppr() << 24) | irq);
> }
>
> -static int xics_set_affinity(unsigned int virq, const struct cpumask *cpumask)
> +static int
> +xics_set_affinity(struct irq_data *d, const struct cpumask *cpumask, bool force)
> {
> unsigned int irq;
> int status;
> int xics_status[2];
> int irq_server;
>
> - irq = (unsigned int)irq_map[virq].hwirq;
> + irq = (unsigned int)irq_map[d->irq].hwirq;
> if (irq == XICS_IPI || irq == XICS_IRQ_SPURIOUS)
> return -1;
>
> @@ -406,13 +407,13 @@ static int xics_set_affinity(unsigned int virq, const struct cpumask *cpumask)
> return -1;
> }
>
> - irq_server = get_irq_server(virq, cpumask, 1);
> + irq_server = get_irq_server(d->irq, cpumask, 1);
> if (irq_server == -1) {
> char cpulist[128];
> cpumask_scnprintf(cpulist, sizeof(cpulist), cpumask);
> printk(KERN_WARNING
> "%s: No online cpus in the mask %s for irq %d\n",
> - __func__, cpulist, virq);
> + __func__, cpulist, d->irq);
> return -1;
> }
>
> @@ -430,20 +431,20 @@ static int xics_set_affinity(unsigned int virq, const struct cpumask *cpumask)
>
> static struct irq_chip xics_pic_direct = {
> .name = "XICS",
> - .startup = xics_startup,
> - .mask = xics_mask_irq,
> - .unmask = xics_unmask_irq,
> - .eoi = xics_eoi_direct,
> - .set_affinity = xics_set_affinity
> + .irq_startup = xics_startup,
> + .irq_mask = xics_mask_irq,
> + .irq_unmask = xics_unmask_irq,
> + .irq_eoi = xics_eoi_direct,
> + .irq_set_affinity = xics_set_affinity
> };
>
> static struct irq_chip xics_pic_lpar = {
> .name = "XICS",
> - .startup = xics_startup,
> - .mask = xics_mask_irq,
> - .unmask = xics_unmask_irq,
> - .eoi = xics_eoi_lpar,
> - .set_affinity = xics_set_affinity
> + .irq_startup = xics_startup,
> + .irq_mask = xics_mask_irq,
> + .irq_unmask = xics_unmask_irq,
> + .irq_eoi = xics_eoi_lpar,
> + .irq_set_affinity = xics_set_affinity
> };
>
>
> @@ -890,6 +891,7 @@ void xics_migrate_irqs_away(void)
>
> for_each_irq(virq) {
> struct irq_desc *desc;
> + struct irq_chip *chip;
> int xics_status[2];
> int status;
> unsigned long flags;
> @@ -903,12 +905,15 @@ void xics_migrate_irqs_away(void)
> /* We need to get IPIs still. */
> if (irq == XICS_IPI || irq == XICS_IRQ_SPURIOUS)
> continue;
> +
> desc = irq_to_desc(virq);
>
> /* We only need to migrate enabled IRQS */
> - if (desc == NULL || desc->chip == NULL
> - || desc->action == NULL
> - || desc->chip->set_affinity == NULL)
> + if (desc == NULL || desc->action == NULL)
> + continue;
> +
> + chip = get_irq_desc_chip(desc);
> + if (chip == NULL || chip->irq_set_affinity == NULL)
> continue;
>
> raw_spin_lock_irqsave(&desc->lock, flags);
> @@ -934,8 +939,8 @@ void xics_migrate_irqs_away(void)
> virq, cpu);
>
> /* Reset affinity to all cpus */
> - cpumask_setall(irq_to_desc(virq)->affinity);
> - desc->chip->set_affinity(virq, cpu_all_mask);
> + cpumask_setall(desc->irq_data.affinity);
> + chip->irq_set_affinity(&desc->irq_data, cpu_all_mask, true);
> unlock:
> raw_spin_unlock_irqrestore(&desc->lock, flags);
> }
> diff --git a/arch/powerpc/sysdev/cpm1.c b/arch/powerpc/sysdev/cpm1.c
> index 0085212..0476bcc 100644
> --- a/arch/powerpc/sysdev/cpm1.c
> +++ b/arch/powerpc/sysdev/cpm1.c
> @@ -56,32 +56,32 @@ static cpic8xx_t __iomem *cpic_reg;
>
> static struct irq_host *cpm_pic_host;
>
> -static void cpm_mask_irq(unsigned int irq)
> +static void cpm_mask_irq(struct irq_data *d)
> {
> - unsigned int cpm_vec = (unsigned int)irq_map[irq].hwirq;
> + unsigned int cpm_vec = (unsigned int)irq_map[d->irq].hwirq;
>
> clrbits32(&cpic_reg->cpic_cimr, (1 << cpm_vec));
> }
>
> -static void cpm_unmask_irq(unsigned int irq)
> +static void cpm_unmask_irq(struct irq_data *d)
> {
> - unsigned int cpm_vec = (unsigned int)irq_map[irq].hwirq;
> + unsigned int cpm_vec = (unsigned int)irq_map[d->irq].hwirq;
>
> setbits32(&cpic_reg->cpic_cimr, (1 << cpm_vec));
> }
>
> -static void cpm_end_irq(unsigned int irq)
> +static void cpm_end_irq(struct irq_data *d)
> {
> - unsigned int cpm_vec = (unsigned int)irq_map[irq].hwirq;
> + unsigned int cpm_vec = (unsigned int)irq_map[d->irq].hwirq;
>
> out_be32(&cpic_reg->cpic_cisr, (1 << cpm_vec));
> }
>
> static struct irq_chip cpm_pic = {
> .name = "CPM PIC",
> - .mask = cpm_mask_irq,
> - .unmask = cpm_unmask_irq,
> - .eoi = cpm_end_irq,
> + .irq_mask = cpm_mask_irq,
> + .irq_unmask = cpm_unmask_irq,
> + .irq_eoi = cpm_end_irq,
> };
>
> int cpm_get_irq(void)
> diff --git a/arch/powerpc/sysdev/cpm2_pic.c b/arch/powerpc/sysdev/cpm2_pic.c
> index fcea4ff..4730325 100644
> --- a/arch/powerpc/sysdev/cpm2_pic.c
> +++ b/arch/powerpc/sysdev/cpm2_pic.c
> @@ -78,10 +78,10 @@ static const u_char irq_to_siubit[] = {
> 24, 25, 26, 27, 28, 29, 30, 31,
> };
>
> -static void cpm2_mask_irq(unsigned int virq)
> +static void cpm2_mask_irq(struct irq_data *d)
> {
> int bit, word;
> - unsigned int irq_nr = virq_to_hw(virq);
> + unsigned int irq_nr = virq_to_hw(d->irq);
>
> bit = irq_to_siubit[irq_nr];
> word = irq_to_siureg[irq_nr];
> @@ -90,10 +90,10 @@ static void cpm2_mask_irq(unsigned int virq)
> out_be32(&cpm2_intctl->ic_simrh + word, ppc_cached_irq_mask[word]);
> }
>
> -static void cpm2_unmask_irq(unsigned int virq)
> +static void cpm2_unmask_irq(struct irq_data *d)
> {
> int bit, word;
> - unsigned int irq_nr = virq_to_hw(virq);
> + unsigned int irq_nr = virq_to_hw(d->irq);
>
> bit = irq_to_siubit[irq_nr];
> word = irq_to_siureg[irq_nr];
> @@ -102,10 +102,10 @@ static void cpm2_unmask_irq(unsigned int virq)
> out_be32(&cpm2_intctl->ic_simrh + word, ppc_cached_irq_mask[word]);
> }
>
> -static void cpm2_ack(unsigned int virq)
> +static void cpm2_ack(struct irq_data *d)
> {
> int bit, word;
> - unsigned int irq_nr = virq_to_hw(virq);
> + unsigned int irq_nr = virq_to_hw(d->irq);
>
> bit = irq_to_siubit[irq_nr];
> word = irq_to_siureg[irq_nr];
> @@ -113,11 +113,11 @@ static void cpm2_ack(unsigned int virq)
> out_be32(&cpm2_intctl->ic_sipnrh + word, 1 << bit);
> }
>
> -static void cpm2_end_irq(unsigned int virq)
> +static void cpm2_end_irq(struct irq_data *d)
> {
> struct irq_desc *desc;
> int bit, word;
> - unsigned int irq_nr = virq_to_hw(virq);
> + unsigned int irq_nr = virq_to_hw(d->irq);
>
> desc = irq_to_desc(irq_nr);
> if (!(desc->status & (IRQ_DISABLED|IRQ_INPROGRESS))
> @@ -137,10 +137,10 @@ static void cpm2_end_irq(unsigned int virq)
> }
> }
>
> -static int cpm2_set_irq_type(unsigned int virq, unsigned int flow_type)
> +static int cpm2_set_irq_type(struct irq_data *d, unsigned int flow_type)
> {
> - unsigned int src = virq_to_hw(virq);
> - struct irq_desc *desc = irq_to_desc(virq);
> + unsigned int src = virq_to_hw(d->irq);
> + struct irq_desc *desc = irq_to_desc(d->irq);
> unsigned int vold, vnew, edibit;
>
> /* Port C interrupts are either IRQ_TYPE_EDGE_FALLING or
> @@ -199,11 +199,11 @@ err_sense:
>
> static struct irq_chip cpm2_pic = {
> .name = "CPM2 SIU",
> - .mask = cpm2_mask_irq,
> - .unmask = cpm2_unmask_irq,
> - .ack = cpm2_ack,
> - .eoi = cpm2_end_irq,
> - .set_type = cpm2_set_irq_type,
> + .irq_mask = cpm2_mask_irq,
> + .irq_unmask = cpm2_unmask_irq,
> + .irq_ack = cpm2_ack,
> + .irq_eoi = cpm2_end_irq,
> + .irq_set_type = cpm2_set_irq_type,
> };
>
> unsigned int cpm2_get_irq(void)
> diff --git a/arch/powerpc/sysdev/fsl_msi.c b/arch/powerpc/sysdev/fsl_msi.c
> index 108d76f..f6051d7 100644
> --- a/arch/powerpc/sysdev/fsl_msi.c
> +++ b/arch/powerpc/sysdev/fsl_msi.c
> @@ -47,14 +47,14 @@ static inline u32 fsl_msi_read(u32 __iomem *base, unsigned int reg)
> * We do not need this actually. The MSIR register has been read once
> * in the cascade interrupt. So, this MSI interrupt has been acked
> */
> -static void fsl_msi_end_irq(unsigned int virq)
> +static void fsl_msi_end_irq(struct irq_data *d)
> {
> }
>
> static struct irq_chip fsl_msi_chip = {
> .irq_mask = mask_msi_irq,
> .irq_unmask = unmask_msi_irq,
> - .ack = fsl_msi_end_irq,
> + .irq_ack = fsl_msi_end_irq,
> .name = "FSL-MSI",
> };
>
> @@ -183,6 +183,7 @@ out_free:
>
> static void fsl_msi_cascade(unsigned int irq, struct irq_desc *desc)
> {
> + struct irq_chip *chip = get_irq_desc_chip(desc);
> unsigned int cascade_irq;
> struct fsl_msi *msi_data;
> int msir_index = -1;
> @@ -196,11 +197,11 @@ static void fsl_msi_cascade(unsigned int irq, struct irq_desc *desc)
>
> raw_spin_lock(&desc->lock);
> if ((msi_data->feature & FSL_PIC_IP_MASK) == FSL_PIC_IP_IPIC) {
> - if (desc->chip->mask_ack)
> - desc->chip->mask_ack(irq);
> + if (chip->irq_mask_ack)
> + chip->irq_mask_ack(&desc->irq_data);
> else {
> - desc->chip->mask(irq);
> - desc->chip->ack(irq);
> + chip->irq_mask(&desc->irq_data);
> + chip->irq_ack(&desc->irq_data);
> }
> }
>
> @@ -238,11 +239,11 @@ static void fsl_msi_cascade(unsigned int irq, struct irq_desc *desc)
>
> switch (msi_data->feature & FSL_PIC_IP_MASK) {
> case FSL_PIC_IP_MPIC:
> - desc->chip->eoi(irq);
> + chip->irq_eoi(&desc->irq_data);
> break;
> case FSL_PIC_IP_IPIC:
> - if (!(desc->status & IRQ_DISABLED) && desc->chip->unmask)
> - desc->chip->unmask(irq);
> + if (!(desc->status & IRQ_DISABLED) && chip->irq_unmask)
> + chip->irq_unmask(&desc->irq_data);
> break;
> }
> unlock:
> diff --git a/arch/powerpc/sysdev/i8259.c b/arch/powerpc/sysdev/i8259.c
> index 6323e70..aeda4c8 100644
> --- a/arch/powerpc/sysdev/i8259.c
> +++ b/arch/powerpc/sysdev/i8259.c
> @@ -78,19 +78,19 @@ unsigned int i8259_irq(void)
> return irq;
> }
>
> -static void i8259_mask_and_ack_irq(unsigned int irq_nr)
> +static void i8259_mask_and_ack_irq(struct irq_data *d)
> {
> unsigned long flags;
>
> raw_spin_lock_irqsave(&i8259_lock, flags);
> - if (irq_nr > 7) {
> - cached_A1 |= 1 << (irq_nr-8);
> + if (d->irq > 7) {
> + cached_A1 |= 1 << (d->irq-8);
> inb(0xA1); /* DUMMY */
> outb(cached_A1, 0xA1);
> outb(0x20, 0xA0); /* Non-specific EOI */
> outb(0x20, 0x20); /* Non-specific EOI to cascade */
> } else {
> - cached_21 |= 1 << irq_nr;
> + cached_21 |= 1 << d->irq;
> inb(0x21); /* DUMMY */
> outb(cached_21, 0x21);
> outb(0x20, 0x20); /* Non-specific EOI */
> @@ -104,42 +104,42 @@ static void i8259_set_irq_mask(int irq_nr)
> outb(cached_21,0x21);
> }
>
> -static void i8259_mask_irq(unsigned int irq_nr)
> +static void i8259_mask_irq(struct irq_data *d)
> {
> unsigned long flags;
>
> - pr_debug("i8259_mask_irq(%d)\n", irq_nr);
> + pr_debug("i8259_mask_irq(%d)\n", d->irq);
>
> raw_spin_lock_irqsave(&i8259_lock, flags);
> - if (irq_nr < 8)
> - cached_21 |= 1 << irq_nr;
> + if (d->irq < 8)
> + cached_21 |= 1 << d->irq;
> else
> - cached_A1 |= 1 << (irq_nr-8);
> - i8259_set_irq_mask(irq_nr);
> + cached_A1 |= 1 << (d->irq-8);
> + i8259_set_irq_mask(d->irq);
> raw_spin_unlock_irqrestore(&i8259_lock, flags);
> }
>
> -static void i8259_unmask_irq(unsigned int irq_nr)
> +static void i8259_unmask_irq(struct irq_data *d)
> {
> unsigned long flags;
>
> - pr_debug("i8259_unmask_irq(%d)\n", irq_nr);
> + pr_debug("i8259_unmask_irq(%d)\n", d->irq);
>
> raw_spin_lock_irqsave(&i8259_lock, flags);
> - if (irq_nr < 8)
> - cached_21 &= ~(1 << irq_nr);
> + if (d->irq < 8)
> + cached_21 &= ~(1 << d->irq);
> else
> - cached_A1 &= ~(1 << (irq_nr-8));
> - i8259_set_irq_mask(irq_nr);
> + cached_A1 &= ~(1 << (d->irq-8));
> + i8259_set_irq_mask(d->irq);
> raw_spin_unlock_irqrestore(&i8259_lock, flags);
> }
>
> static struct irq_chip i8259_pic = {
> .name = "i8259",
> - .mask = i8259_mask_irq,
> - .disable = i8259_mask_irq,
> - .unmask = i8259_unmask_irq,
> - .mask_ack = i8259_mask_and_ack_irq,
> + .irq_mask = i8259_mask_irq,
> + .irq_disable = i8259_mask_irq,
> + .irq_unmask = i8259_unmask_irq,
> + .irq_mask_ack = i8259_mask_and_ack_irq,
> };
>
> static struct resource pic1_iores = {
> @@ -188,7 +188,7 @@ static int i8259_host_map(struct irq_host *h, unsigned int virq,
> static void i8259_host_unmap(struct irq_host *h, unsigned int virq)
> {
> /* Make sure irq is masked in hardware */
> - i8259_mask_irq(virq);
> + i8259_mask_irq(irq_get_irq_data(virq));
>
> /* remove chip and handler */
> set_irq_chip_and_handler(virq, NULL, NULL);
> diff --git a/arch/powerpc/sysdev/ipic.c b/arch/powerpc/sysdev/ipic.c
> index d7b9b9c..497047d 100644
> --- a/arch/powerpc/sysdev/ipic.c
> +++ b/arch/powerpc/sysdev/ipic.c
> @@ -523,10 +523,10 @@ static inline struct ipic * ipic_from_irq(unsigned int virq)
>
> #define ipic_irq_to_hw(virq) ((unsigned int)irq_map[virq].hwirq)
>
> -static void ipic_unmask_irq(unsigned int virq)
> +static void ipic_unmask_irq(struct irq_data *d)
> {
> - struct ipic *ipic = ipic_from_irq(virq);
> - unsigned int src = ipic_irq_to_hw(virq);
> + struct ipic *ipic = ipic_from_irq(d->irq);
> + unsigned int src = ipic_irq_to_hw(d->irq);
> unsigned long flags;
> u32 temp;
>
> @@ -539,10 +539,10 @@ static void ipic_unmask_irq(unsigned int virq)
> raw_spin_unlock_irqrestore(&ipic_lock, flags);
> }
>
> -static void ipic_mask_irq(unsigned int virq)
> +static void ipic_mask_irq(struct irq_data *d)
> {
> - struct ipic *ipic = ipic_from_irq(virq);
> - unsigned int src = ipic_irq_to_hw(virq);
> + struct ipic *ipic = ipic_from_irq(d->irq);
> + unsigned int src = ipic_irq_to_hw(d->irq);
> unsigned long flags;
> u32 temp;
>
> @@ -559,10 +559,10 @@ static void ipic_mask_irq(unsigned int virq)
> raw_spin_unlock_irqrestore(&ipic_lock, flags);
> }
>
> -static void ipic_ack_irq(unsigned int virq)
> +static void ipic_ack_irq(struct irq_data *d)
> {
> - struct ipic *ipic = ipic_from_irq(virq);
> - unsigned int src = ipic_irq_to_hw(virq);
> + struct ipic *ipic = ipic_from_irq(d->irq);
> + unsigned int src = ipic_irq_to_hw(d->irq);
> unsigned long flags;
> u32 temp;
>
> @@ -578,10 +578,10 @@ static void ipic_ack_irq(unsigned int virq)
> raw_spin_unlock_irqrestore(&ipic_lock, flags);
> }
>
> -static void ipic_mask_irq_and_ack(unsigned int virq)
> +static void ipic_mask_irq_and_ack(struct irq_data *d)
> {
> - struct ipic *ipic = ipic_from_irq(virq);
> - unsigned int src = ipic_irq_to_hw(virq);
> + struct ipic *ipic = ipic_from_irq(d->irq);
> + unsigned int src = ipic_irq_to_hw(d->irq);
> unsigned long flags;
> u32 temp;
>
> @@ -601,11 +601,11 @@ static void ipic_mask_irq_and_ack(unsigned int virq)
> raw_spin_unlock_irqrestore(&ipic_lock, flags);
> }
>
> -static int ipic_set_irq_type(unsigned int virq, unsigned int flow_type)
> +static int ipic_set_irq_type(struct irq_data *d, unsigned int flow_type)
> {
> - struct ipic *ipic = ipic_from_irq(virq);
> - unsigned int src = ipic_irq_to_hw(virq);
> - struct irq_desc *desc = irq_to_desc(virq);
> + struct ipic *ipic = ipic_from_irq(d->irq);
> + unsigned int src = ipic_irq_to_hw(d->irq);
> + struct irq_desc *desc = irq_to_desc(d->irq);
> unsigned int vold, vnew, edibit;
>
> if (flow_type == IRQ_TYPE_NONE)
> @@ -630,10 +630,10 @@ static int ipic_set_irq_type(unsigned int virq, unsigned int flow_type)
> if (flow_type & IRQ_TYPE_LEVEL_LOW) {
> desc->status |= IRQ_LEVEL;
> desc->handle_irq = handle_level_irq;
> - desc->chip = &ipic_level_irq_chip;
> + desc->irq_data.chip = &ipic_level_irq_chip;
> } else {
> desc->handle_irq = handle_edge_irq;
> - desc->chip = &ipic_edge_irq_chip;
> + desc->irq_data.chip = &ipic_edge_irq_chip;
> }
>
> /* only EXT IRQ senses are programmable on ipic
> @@ -661,19 +661,19 @@ static int ipic_set_irq_type(unsigned int virq, unsigned int flow_type)
> /* level interrupts and edge interrupts have different ack operations */
> static struct irq_chip ipic_level_irq_chip = {
> .name = "IPIC",
> - .unmask = ipic_unmask_irq,
> - .mask = ipic_mask_irq,
> - .mask_ack = ipic_mask_irq,
> - .set_type = ipic_set_irq_type,
> + .irq_unmask = ipic_unmask_irq,
> + .irq_mask = ipic_mask_irq,
> + .irq_mask_ack = ipic_mask_irq,
> + .irq_set_type = ipic_set_irq_type,
> };
>
> static struct irq_chip ipic_edge_irq_chip = {
> .name = "IPIC",
> - .unmask = ipic_unmask_irq,
> - .mask = ipic_mask_irq,
> - .mask_ack = ipic_mask_irq_and_ack,
> - .ack = ipic_ack_irq,
> - .set_type = ipic_set_irq_type,
> + .irq_unmask = ipic_unmask_irq,
> + .irq_mask = ipic_mask_irq,
> + .irq_mask_ack = ipic_mask_irq_and_ack,
> + .irq_ack = ipic_ack_irq,
> + .irq_set_type = ipic_set_irq_type,
> };
>
> static int ipic_host_match(struct irq_host *h, struct device_node *node)
> diff --git a/arch/powerpc/sysdev/mpc8xx_pic.c b/arch/powerpc/sysdev/mpc8xx_pic.c
> index 8c27d26..1a75a7f 100644
> --- a/arch/powerpc/sysdev/mpc8xx_pic.c
> +++ b/arch/powerpc/sysdev/mpc8xx_pic.c
> @@ -25,10 +25,10 @@ static sysconf8xx_t __iomem *siu_reg;
>
> int cpm_get_irq(struct pt_regs *regs);
>
> -static void mpc8xx_unmask_irq(unsigned int virq)
> +static void mpc8xx_unmask_irq(struct irq_data *d)
> {
> int bit, word;
> - unsigned int irq_nr = (unsigned int)irq_map[virq].hwirq;
> + unsigned int irq_nr = (unsigned int)irq_map[d->irq].hwirq;
>
> bit = irq_nr & 0x1f;
> word = irq_nr >> 5;
> @@ -37,10 +37,10 @@ static void mpc8xx_unmask_irq(unsigned int virq)
> out_be32(&siu_reg->sc_simask, ppc_cached_irq_mask[word]);
> }
>
> -static void mpc8xx_mask_irq(unsigned int virq)
> +static void mpc8xx_mask_irq(struct irq_data *d)
> {
> int bit, word;
> - unsigned int irq_nr = (unsigned int)irq_map[virq].hwirq;
> + unsigned int irq_nr = (unsigned int)irq_map[d->irq].hwirq;
>
> bit = irq_nr & 0x1f;
> word = irq_nr >> 5;
> @@ -49,19 +49,19 @@ static void mpc8xx_mask_irq(unsigned int virq)
> out_be32(&siu_reg->sc_simask, ppc_cached_irq_mask[word]);
> }
>
> -static void mpc8xx_ack(unsigned int virq)
> +static void mpc8xx_ack(struct irq_data *d)
> {
> int bit;
> - unsigned int irq_nr = (unsigned int)irq_map[virq].hwirq;
> + unsigned int irq_nr = (unsigned int)irq_map[d->irq].hwirq;
>
> bit = irq_nr & 0x1f;
> out_be32(&siu_reg->sc_sipend, 1 << (31-bit));
> }
>
> -static void mpc8xx_end_irq(unsigned int virq)
> +static void mpc8xx_end_irq(struct irq_data *d)
> {
> int bit, word;
> - unsigned int irq_nr = (unsigned int)irq_map[virq].hwirq;
> + unsigned int irq_nr = (unsigned int)irq_map[d->irq].hwirq;
>
> bit = irq_nr & 0x1f;
> word = irq_nr >> 5;
> @@ -70,9 +70,9 @@ static void mpc8xx_end_irq(unsigned int virq)
> out_be32(&siu_reg->sc_simask, ppc_cached_irq_mask[word]);
> }
>
> -static int mpc8xx_set_irq_type(unsigned int virq, unsigned int flow_type)
> +static int mpc8xx_set_irq_type(struct irq_data *d, unsigned int flow_type)
> {
> - struct irq_desc *desc = irq_to_desc(virq);
> + struct irq_desc *desc = irq_to_desc(d->irq);
>
> desc->status &= ~(IRQ_TYPE_SENSE_MASK | IRQ_LEVEL);
> desc->status |= flow_type & IRQ_TYPE_SENSE_MASK;
> @@ -80,7 +80,7 @@ static int mpc8xx_set_irq_type(unsigned int virq, unsigned int flow_type)
> desc->status |= IRQ_LEVEL;
>
> if (flow_type & IRQ_TYPE_EDGE_FALLING) {
> - irq_hw_number_t hw = (unsigned int)irq_map[virq].hwirq;
> + irq_hw_number_t hw = (unsigned int)irq_map[d->irq].hwirq;
> unsigned int siel = in_be32(&siu_reg->sc_siel);
>
> /* only external IRQ senses are programmable */
> @@ -95,11 +95,11 @@ static int mpc8xx_set_irq_type(unsigned int virq, unsigned int flow_type)
>
> static struct irq_chip mpc8xx_pic = {
> .name = "MPC8XX SIU",
> - .unmask = mpc8xx_unmask_irq,
> - .mask = mpc8xx_mask_irq,
> - .ack = mpc8xx_ack,
> - .eoi = mpc8xx_end_irq,
> - .set_type = mpc8xx_set_irq_type,
> + .irq_unmask = mpc8xx_unmask_irq,
> + .irq_mask = mpc8xx_mask_irq,
> + .irq_ack = mpc8xx_ack,
> + .irq_eoi = mpc8xx_end_irq,
> + .irq_set_type = mpc8xx_set_irq_type,
> };
>
> unsigned int mpc8xx_get_irq(void)
> diff --git a/arch/powerpc/sysdev/mpc8xxx_gpio.c b/arch/powerpc/sysdev/mpc8xxx_gpio.c
> index c48cd81..519a877 100644
> --- a/arch/powerpc/sysdev/mpc8xxx_gpio.c
> +++ b/arch/powerpc/sysdev/mpc8xxx_gpio.c
> @@ -155,43 +155,43 @@ static void mpc8xxx_gpio_irq_cascade(unsigned int irq, struct irq_desc *desc)
> 32 - ffs(mask)));
> }
>
> -static void mpc8xxx_irq_unmask(unsigned int virq)
> +static void mpc8xxx_irq_unmask(struct irq_data *d)
> {
> - struct mpc8xxx_gpio_chip *mpc8xxx_gc = get_irq_chip_data(virq);
> + struct mpc8xxx_gpio_chip *mpc8xxx_gc = get_irq_chip_data(d->irq);
> struct of_mm_gpio_chip *mm = &mpc8xxx_gc->mm_gc;
> unsigned long flags;
>
> spin_lock_irqsave(&mpc8xxx_gc->lock, flags);
>
> - setbits32(mm->regs + GPIO_IMR, mpc8xxx_gpio2mask(virq_to_hw(virq)));
> + setbits32(mm->regs + GPIO_IMR, mpc8xxx_gpio2mask(virq_to_hw(d->irq)));
>
> spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags);
> }
>
> -static void mpc8xxx_irq_mask(unsigned int virq)
> +static void mpc8xxx_irq_mask(struct irq_data *d)
> {
> - struct mpc8xxx_gpio_chip *mpc8xxx_gc = get_irq_chip_data(virq);
> + struct mpc8xxx_gpio_chip *mpc8xxx_gc = get_irq_chip_data(d->irq);
> struct of_mm_gpio_chip *mm = &mpc8xxx_gc->mm_gc;
> unsigned long flags;
>
> spin_lock_irqsave(&mpc8xxx_gc->lock, flags);
>
> - clrbits32(mm->regs + GPIO_IMR, mpc8xxx_gpio2mask(virq_to_hw(virq)));
> + clrbits32(mm->regs + GPIO_IMR, mpc8xxx_gpio2mask(virq_to_hw(d->irq)));
>
> spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags);
> }
>
> -static void mpc8xxx_irq_ack(unsigned int virq)
> +static void mpc8xxx_irq_ack(struct irq_data *d)
> {
> - struct mpc8xxx_gpio_chip *mpc8xxx_gc = get_irq_chip_data(virq);
> + struct mpc8xxx_gpio_chip *mpc8xxx_gc = get_irq_chip_data(d->irq);
> struct of_mm_gpio_chip *mm = &mpc8xxx_gc->mm_gc;
>
> - out_be32(mm->regs + GPIO_IER, mpc8xxx_gpio2mask(virq_to_hw(virq)));
> + out_be32(mm->regs + GPIO_IER, mpc8xxx_gpio2mask(virq_to_hw(d->irq)));
> }
>
> -static int mpc8xxx_irq_set_type(unsigned int virq, unsigned int flow_type)
> +static int mpc8xxx_irq_set_type(struct irq_data *d, unsigned int flow_type)
> {
> - struct mpc8xxx_gpio_chip *mpc8xxx_gc = get_irq_chip_data(virq);
> + struct mpc8xxx_gpio_chip *mpc8xxx_gc = get_irq_chip_data(d->irq);
> struct of_mm_gpio_chip *mm = &mpc8xxx_gc->mm_gc;
> unsigned long flags;
>
> @@ -199,14 +199,14 @@ static int mpc8xxx_irq_set_type(unsigned int virq, unsigned int flow_type)
> case IRQ_TYPE_EDGE_FALLING:
> spin_lock_irqsave(&mpc8xxx_gc->lock, flags);
> setbits32(mm->regs + GPIO_ICR,
> - mpc8xxx_gpio2mask(virq_to_hw(virq)));
> + mpc8xxx_gpio2mask(virq_to_hw(d->irq)));
> spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags);
> break;
>
> case IRQ_TYPE_EDGE_BOTH:
> spin_lock_irqsave(&mpc8xxx_gc->lock, flags);
> clrbits32(mm->regs + GPIO_ICR,
> - mpc8xxx_gpio2mask(virq_to_hw(virq)));
> + mpc8xxx_gpio2mask(virq_to_hw(d->irq)));
> spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags);
> break;
>
> @@ -217,11 +217,11 @@ static int mpc8xxx_irq_set_type(unsigned int virq, unsigned int flow_type)
> return 0;
> }
>
> -static int mpc512x_irq_set_type(unsigned int virq, unsigned int flow_type)
> +static int mpc512x_irq_set_type(struct irq_data *d, unsigned int flow_type)
> {
> - struct mpc8xxx_gpio_chip *mpc8xxx_gc = get_irq_chip_data(virq);
> + struct mpc8xxx_gpio_chip *mpc8xxx_gc = get_irq_chip_data(d->irq);
> struct of_mm_gpio_chip *mm = &mpc8xxx_gc->mm_gc;
> - unsigned long gpio = virq_to_hw(virq);
> + unsigned long gpio = virq_to_hw(d->irq);
> void __iomem *reg;
> unsigned int shift;
> unsigned long flags;
> @@ -264,10 +264,10 @@ static int mpc512x_irq_set_type(unsigned int virq, unsigned int flow_type)
>
> static struct irq_chip mpc8xxx_irq_chip = {
> .name = "mpc8xxx-gpio",
> - .unmask = mpc8xxx_irq_unmask,
> - .mask = mpc8xxx_irq_mask,
> - .ack = mpc8xxx_irq_ack,
> - .set_type = mpc8xxx_irq_set_type,
> + .irq_unmask = mpc8xxx_irq_unmask,
> + .irq_mask = mpc8xxx_irq_mask,
> + .irq_ack = mpc8xxx_irq_ack,
> + .irq_set_type = mpc8xxx_irq_set_type,
> };
>
> static int mpc8xxx_gpio_irq_map(struct irq_host *h, unsigned int virq,
> @@ -276,7 +276,7 @@ static int mpc8xxx_gpio_irq_map(struct irq_host *h, unsigned int virq,
> struct mpc8xxx_gpio_chip *mpc8xxx_gc = h->host_data;
>
> if (mpc8xxx_gc->of_dev_id_data)
> - mpc8xxx_irq_chip.set_type = mpc8xxx_gc->of_dev_id_data;
> + mpc8xxx_irq_chip.irq_set_type = mpc8xxx_gc->of_dev_id_data;
>
> set_irq_chip_data(virq, h->host_data);
> set_irq_chip_and_handler(virq, &mpc8xxx_irq_chip, handle_level_irq);
> diff --git a/arch/powerpc/sysdev/mpic.c b/arch/powerpc/sysdev/mpic.c
> index b0c8469..83b34eb 100644
> --- a/arch/powerpc/sysdev/mpic.c
> +++ b/arch/powerpc/sysdev/mpic.c
> @@ -611,7 +611,7 @@ static struct mpic *mpic_find(unsigned int irq)
> if (irq < NUM_ISA_INTERRUPTS)
> return NULL;
>
> - return irq_to_desc(irq)->chip_data;
> + return get_irq_chip_data(irq);
> }
>
> /* Determine if the linux irq is an IPI */
> @@ -645,7 +645,7 @@ static inline struct mpic * mpic_from_ipi(unsigned int ipi)
> /* Get the mpic structure from the irq number */
> static inline struct mpic * mpic_from_irq(unsigned int irq)
> {
> - return irq_to_desc(irq)->chip_data;
> + return get_irq_chip_data(irq);
> }
>
> /* Send an EOI */
> @@ -660,13 +660,13 @@ static inline void mpic_eoi(struct mpic *mpic)
> */
>
>
> -void mpic_unmask_irq(unsigned int irq)
> +void mpic_unmask_irq(struct irq_data *d)
> {
> unsigned int loops = 100000;
> - struct mpic *mpic = mpic_from_irq(irq);
> - unsigned int src = mpic_irq_to_hw(irq);
> + struct mpic *mpic = mpic_from_irq(d->irq);
> + unsigned int src = mpic_irq_to_hw(d->irq);
>
> - DBG("%p: %s: enable_irq: %d (src %d)\n", mpic, mpic->name, irq, src);
> + DBG("%p: %s: enable_irq: %d (src %d)\n", mpic, mpic->name, d->irq, src);
>
> mpic_irq_write(src, MPIC_INFO(IRQ_VECTOR_PRI),
> mpic_irq_read(src, MPIC_INFO(IRQ_VECTOR_PRI)) &
> @@ -681,13 +681,13 @@ void mpic_unmask_irq(unsigned int irq)
> } while(mpic_irq_read(src, MPIC_INFO(IRQ_VECTOR_PRI)) & MPIC_VECPRI_MASK);
> }
>
> -void mpic_mask_irq(unsigned int irq)
> +void mpic_mask_irq(struct irq_data *d)
> {
> unsigned int loops = 100000;
> - struct mpic *mpic = mpic_from_irq(irq);
> - unsigned int src = mpic_irq_to_hw(irq);
> + struct mpic *mpic = mpic_from_irq(d->irq);
> + unsigned int src = mpic_irq_to_hw(d->irq);
>
> - DBG("%s: disable_irq: %d (src %d)\n", mpic->name, irq, src);
> + DBG("%s: disable_irq: %d (src %d)\n", mpic->name, d->irq, src);
>
> mpic_irq_write(src, MPIC_INFO(IRQ_VECTOR_PRI),
> mpic_irq_read(src, MPIC_INFO(IRQ_VECTOR_PRI)) |
> @@ -703,12 +703,12 @@ void mpic_mask_irq(unsigned int irq)
> } while(!(mpic_irq_read(src, MPIC_INFO(IRQ_VECTOR_PRI)) & MPIC_VECPRI_MASK));
> }
>
> -void mpic_end_irq(unsigned int irq)
> +void mpic_end_irq(struct irq_data *d)
> {
> - struct mpic *mpic = mpic_from_irq(irq);
> + struct mpic *mpic = mpic_from_irq(d->irq);
>
> #ifdef DEBUG_IRQ
> - DBG("%s: end_irq: %d\n", mpic->name, irq);
> + DBG("%s: end_irq: %d\n", mpic->name, d->irq);
> #endif
> /* We always EOI on end_irq() even for edge interrupts since that
> * should only lower the priority, the MPIC should have properly
> @@ -720,51 +720,51 @@ void mpic_end_irq(unsigned int irq)
>
> #ifdef CONFIG_MPIC_U3_HT_IRQS
>
> -static void mpic_unmask_ht_irq(unsigned int irq)
> +static void mpic_unmask_ht_irq(struct irq_data *d)
> {
> - struct mpic *mpic = mpic_from_irq(irq);
> - unsigned int src = mpic_irq_to_hw(irq);
> + struct mpic *mpic = mpic_from_irq(d->irq);
> + unsigned int src = mpic_irq_to_hw(d->irq);
>
> - mpic_unmask_irq(irq);
> + mpic_unmask_irq(d);
>
> - if (irq_to_desc(irq)->status & IRQ_LEVEL)
> + if (irq_to_desc(d->irq)->status & IRQ_LEVEL)
> mpic_ht_end_irq(mpic, src);
> }
>
> -static unsigned int mpic_startup_ht_irq(unsigned int irq)
> +static unsigned int mpic_startup_ht_irq(struct irq_data *d)
> {
> - struct mpic *mpic = mpic_from_irq(irq);
> - unsigned int src = mpic_irq_to_hw(irq);
> + struct mpic *mpic = mpic_from_irq(d->irq);
> + unsigned int src = mpic_irq_to_hw(d->irq);
>
> - mpic_unmask_irq(irq);
> - mpic_startup_ht_interrupt(mpic, src, irq_to_desc(irq)->status);
> + mpic_unmask_irq(d);
> + mpic_startup_ht_interrupt(mpic, src, irq_to_desc(d->irq)->status);
>
> return 0;
> }
>
> -static void mpic_shutdown_ht_irq(unsigned int irq)
> +static void mpic_shutdown_ht_irq(struct irq_data *d)
> {
> - struct mpic *mpic = mpic_from_irq(irq);
> - unsigned int src = mpic_irq_to_hw(irq);
> + struct mpic *mpic = mpic_from_irq(d->irq);
> + unsigned int src = mpic_irq_to_hw(d->irq);
>
> - mpic_shutdown_ht_interrupt(mpic, src, irq_to_desc(irq)->status);
> - mpic_mask_irq(irq);
> + mpic_shutdown_ht_interrupt(mpic, src, irq_to_desc(d->irq)->status);
> + mpic_mask_irq(d);
> }
>
> -static void mpic_end_ht_irq(unsigned int irq)
> +static void mpic_end_ht_irq(struct irq_data *d)
> {
> - struct mpic *mpic = mpic_from_irq(irq);
> - unsigned int src = mpic_irq_to_hw(irq);
> + struct mpic *mpic = mpic_from_irq(d->irq);
> + unsigned int src = mpic_irq_to_hw(d->irq);
>
> #ifdef DEBUG_IRQ
> - DBG("%s: end_irq: %d\n", mpic->name, irq);
> + DBG("%s: end_irq: %d\n", mpic->name, d->irq);
> #endif
> /* We always EOI on end_irq() even for edge interrupts since that
> * should only lower the priority, the MPIC should have properly
> * latched another edge interrupt coming in anyway
> */
>
> - if (irq_to_desc(irq)->status & IRQ_LEVEL)
> + if (irq_to_desc(d->irq)->status & IRQ_LEVEL)
> mpic_ht_end_irq(mpic, src);
> mpic_eoi(mpic);
> }
> @@ -772,23 +772,23 @@ static void mpic_end_ht_irq(unsigned int irq)
>
> #ifdef CONFIG_SMP
>
> -static void mpic_unmask_ipi(unsigned int irq)
> +static void mpic_unmask_ipi(struct irq_data *d)
> {
> - struct mpic *mpic = mpic_from_ipi(irq);
> - unsigned int src = mpic_irq_to_hw(irq) - mpic->ipi_vecs[0];
> + struct mpic *mpic = mpic_from_ipi(d->irq);
> + unsigned int src = mpic_irq_to_hw(d->irq) - mpic->ipi_vecs[0];
>
> - DBG("%s: enable_ipi: %d (ipi %d)\n", mpic->name, irq, src);
> + DBG("%s: enable_ipi: %d (ipi %d)\n", mpic->name, d->irq, src);
> mpic_ipi_write(src, mpic_ipi_read(src) & ~MPIC_VECPRI_MASK);
> }
>
> -static void mpic_mask_ipi(unsigned int irq)
> +static void mpic_mask_ipi(struct irq_data *d)
> {
> /* NEVER disable an IPI... that's just plain wrong! */
> }
>
> -static void mpic_end_ipi(unsigned int irq)
> +static void mpic_end_ipi(struct irq_data *d)
> {
> - struct mpic *mpic = mpic_from_ipi(irq);
> + struct mpic *mpic = mpic_from_ipi(d->irq);
>
> /*
> * IPIs are marked IRQ_PER_CPU. This has the side effect of
> @@ -802,10 +802,11 @@ static void mpic_end_ipi(unsigned int irq)
>
> #endif /* CONFIG_SMP */
>
> -int mpic_set_affinity(unsigned int irq, const struct cpumask *cpumask)
> +int mpic_set_affinity(struct irq_data *d, const struct cpumask *cpumask,
> + bool force)
> {
> - struct mpic *mpic = mpic_from_irq(irq);
> - unsigned int src = mpic_irq_to_hw(irq);
> + struct mpic *mpic = mpic_from_irq(d->irq);
> + unsigned int src = mpic_irq_to_hw(d->irq);
>
> if (mpic->flags & MPIC_SINGLE_DEST_CPU) {
> int cpuid = irq_choose_cpu(cpumask);
> @@ -848,15 +849,15 @@ static unsigned int mpic_type_to_vecpri(struct mpic *mpic, unsigned int type)
> }
> }
>
> -int mpic_set_irq_type(unsigned int virq, unsigned int flow_type)
> +int mpic_set_irq_type(struct irq_data *d, unsigned int flow_type)
> {
> - struct mpic *mpic = mpic_from_irq(virq);
> - unsigned int src = mpic_irq_to_hw(virq);
> - struct irq_desc *desc = irq_to_desc(virq);
> + struct mpic *mpic = mpic_from_irq(d->irq);
> + unsigned int src = mpic_irq_to_hw(d->irq);
> + struct irq_desc *desc = irq_to_desc(d->irq);
> unsigned int vecpri, vold, vnew;
>
> DBG("mpic: set_irq_type(mpic:@%p,virq:%d,src:0x%x,type:0x%x)\n",
> - mpic, virq, src, flow_type);
> + mpic, d->irq, src, flow_type);
>
> if (src >= mpic->irq_count)
> return -EINVAL;
> @@ -907,28 +908,28 @@ void mpic_set_vector(unsigned int virq, unsigned int vector)
> }
>
> static struct irq_chip mpic_irq_chip = {
> - .mask = mpic_mask_irq,
> - .unmask = mpic_unmask_irq,
> - .eoi = mpic_end_irq,
> - .set_type = mpic_set_irq_type,
> + .irq_mask = mpic_mask_irq,
> + .irq_unmask = mpic_unmask_irq,
> + .irq_eoi = mpic_end_irq,
> + .irq_set_type = mpic_set_irq_type,
> };
>
> #ifdef CONFIG_SMP
> static struct irq_chip mpic_ipi_chip = {
> - .mask = mpic_mask_ipi,
> - .unmask = mpic_unmask_ipi,
> - .eoi = mpic_end_ipi,
> + .irq_mask = mpic_mask_ipi,
> + .irq_unmask = mpic_unmask_ipi,
> + .irq_eoi = mpic_end_ipi,
> };
> #endif /* CONFIG_SMP */
>
> #ifdef CONFIG_MPIC_U3_HT_IRQS
> static struct irq_chip mpic_irq_ht_chip = {
> - .startup = mpic_startup_ht_irq,
> - .shutdown = mpic_shutdown_ht_irq,
> - .mask = mpic_mask_irq,
> - .unmask = mpic_unmask_ht_irq,
> - .eoi = mpic_end_ht_irq,
> - .set_type = mpic_set_irq_type,
> + .irq_startup = mpic_startup_ht_irq,
> + .irq_shutdown = mpic_shutdown_ht_irq,
> + .irq_mask = mpic_mask_irq,
> + .irq_unmask = mpic_unmask_ht_irq,
> + .irq_eoi = mpic_end_ht_irq,
> + .irq_set_type = mpic_set_irq_type,
> };
> #endif /* CONFIG_MPIC_U3_HT_IRQS */
>
> @@ -1060,12 +1061,12 @@ struct mpic * __init mpic_alloc(struct device_node *node,
> mpic->hc_irq = mpic_irq_chip;
> mpic->hc_irq.name = name;
> if (flags & MPIC_PRIMARY)
> - mpic->hc_irq.set_affinity = mpic_set_affinity;
> + mpic->hc_irq.irq_set_affinity = mpic_set_affinity;
> #ifdef CONFIG_MPIC_U3_HT_IRQS
> mpic->hc_ht_irq = mpic_irq_ht_chip;
> mpic->hc_ht_irq.name = name;
> if (flags & MPIC_PRIMARY)
> - mpic->hc_ht_irq.set_affinity = mpic_set_affinity;
> + mpic->hc_ht_irq.irq_set_affinity = mpic_set_affinity;
> #endif /* CONFIG_MPIC_U3_HT_IRQS */
>
> #ifdef CONFIG_SMP
> diff --git a/arch/powerpc/sysdev/mpic.h b/arch/powerpc/sysdev/mpic.h
> index e4a6df7..13f3e89 100644
> --- a/arch/powerpc/sysdev/mpic.h
> +++ b/arch/powerpc/sysdev/mpic.h
> @@ -34,9 +34,10 @@ static inline int mpic_pasemi_msi_init(struct mpic *mpic)
> }
> #endif
>
> -extern int mpic_set_irq_type(unsigned int virq, unsigned int flow_type);
> +extern int mpic_set_irq_type(struct irq_data *d, unsigned int flow_type);
> extern void mpic_set_vector(unsigned int virq, unsigned int vector);
> -extern int mpic_set_affinity(unsigned int irq, const struct cpumask *cpumask);
> +extern int mpic_set_affinity(struct irq_data *d,
> + const struct cpumask *cpumask, bool force);
> extern void mpic_reset_core(int cpu);
>
> #endif /* _POWERPC_SYSDEV_MPIC_H */
> diff --git a/arch/powerpc/sysdev/mpic_pasemi_msi.c b/arch/powerpc/sysdev/mpic_pasemi_msi.c
> index 320ad5a..0b7794a 100644
> --- a/arch/powerpc/sysdev/mpic_pasemi_msi.c
> +++ b/arch/powerpc/sysdev/mpic_pasemi_msi.c
> @@ -43,24 +43,24 @@ static void mpic_pasemi_msi_mask_irq(struct irq_data *data)
> {
> pr_debug("mpic_pasemi_msi_mask_irq %d\n", data->irq);
> mask_msi_irq(data);
> - mpic_mask_irq(data->irq);
> + mpic_mask_irq(data);
> }
>
> static void mpic_pasemi_msi_unmask_irq(struct irq_data *data)
> {
> pr_debug("mpic_pasemi_msi_unmask_irq %d\n", data->irq);
> - mpic_unmask_irq(data->irq);
> + mpic_unmask_irq(data);
> unmask_msi_irq(data);
> }
>
> static struct irq_chip mpic_pasemi_msi_chip = {
> - .irq_shutdown = mpic_pasemi_msi_mask_irq,
> - .irq_mask = mpic_pasemi_msi_mask_irq,
> - .irq_unmask = mpic_pasemi_msi_unmask_irq,
> - .eoi = mpic_end_irq,
> - .set_type = mpic_set_irq_type,
> - .set_affinity = mpic_set_affinity,
> - .name = "PASEMI-MSI",
> + .irq_shutdown = mpic_pasemi_msi_mask_irq,
> + .irq_mask = mpic_pasemi_msi_mask_irq,
> + .irq_unmask = mpic_pasemi_msi_unmask_irq,
> + .irq_eoi = mpic_end_irq,
> + .irq_set_type = mpic_set_irq_type,
> + .irq_set_affinity = mpic_set_affinity,
> + .name = "PASEMI-MSI",
> };
>
> static int pasemi_msi_check_device(struct pci_dev *pdev, int nvec, int type)
> diff --git a/arch/powerpc/sysdev/mpic_u3msi.c b/arch/powerpc/sysdev/mpic_u3msi.c
> index a2b028b..71900ac 100644
> --- a/arch/powerpc/sysdev/mpic_u3msi.c
> +++ b/arch/powerpc/sysdev/mpic_u3msi.c
> @@ -26,23 +26,23 @@ static struct mpic *msi_mpic;
> static void mpic_u3msi_mask_irq(struct irq_data *data)
> {
> mask_msi_irq(data);
> - mpic_mask_irq(data->irq);
> + mpic_mask_irq(data);
> }
>
> static void mpic_u3msi_unmask_irq(struct irq_data *data)
> {
> - mpic_unmask_irq(data->irq);
> + mpic_unmask_irq(data);
> unmask_msi_irq(data);
> }
>
> static struct irq_chip mpic_u3msi_chip = {
> - .irq_shutdown = mpic_u3msi_mask_irq,
> - .irq_mask = mpic_u3msi_mask_irq,
> - .irq_unmask = mpic_u3msi_unmask_irq,
> - .eoi = mpic_end_irq,
> - .set_type = mpic_set_irq_type,
> - .set_affinity = mpic_set_affinity,
> - .name = "MPIC-U3MSI",
> + .irq_shutdown = mpic_u3msi_mask_irq,
> + .irq_mask = mpic_u3msi_mask_irq,
> + .irq_unmask = mpic_u3msi_unmask_irq,
> + .irq_eoi = mpic_end_irq,
> + .irq_set_type = mpic_set_irq_type,
> + .irq_set_affinity = mpic_set_affinity,
> + .name = "MPIC-U3MSI",
> };
>
> static u64 read_ht_magic_addr(struct pci_dev *pdev, unsigned int pos)
> diff --git a/arch/powerpc/sysdev/mv64x60_pic.c b/arch/powerpc/sysdev/mv64x60_pic.c
> index 485b924..bc61ebb 100644
> --- a/arch/powerpc/sysdev/mv64x60_pic.c
> +++ b/arch/powerpc/sysdev/mv64x60_pic.c
> @@ -76,9 +76,9 @@ static struct irq_host *mv64x60_irq_host;
> * mv64x60_chip_low functions
> */
>
> -static void mv64x60_mask_low(unsigned int virq)
> +static void mv64x60_mask_low(struct irq_data *d)
> {
> - int level2 = irq_map[virq].hwirq & MV64x60_LEVEL2_MASK;
> + int level2 = irq_map[d->irq].hwirq & MV64x60_LEVEL2_MASK;
> unsigned long flags;
>
> spin_lock_irqsave(&mv64x60_lock, flags);
> @@ -89,9 +89,9 @@ static void mv64x60_mask_low(unsigned int virq)
> (void)in_le32(mv64x60_irq_reg_base + MV64X60_IC_CPU0_INTR_MASK_LO);
> }
>
> -static void mv64x60_unmask_low(unsigned int virq)
> +static void mv64x60_unmask_low(struct irq_data *d)
> {
> - int level2 = irq_map[virq].hwirq & MV64x60_LEVEL2_MASK;
> + int level2 = irq_map[d->irq].hwirq & MV64x60_LEVEL2_MASK;
> unsigned long flags;
>
> spin_lock_irqsave(&mv64x60_lock, flags);
> @@ -104,18 +104,18 @@ static void mv64x60_unmask_low(unsigned int virq)
>
> static struct irq_chip mv64x60_chip_low = {
> .name = "mv64x60_low",
> - .mask = mv64x60_mask_low,
> - .mask_ack = mv64x60_mask_low,
> - .unmask = mv64x60_unmask_low,
> + .irq_mask = mv64x60_mask_low,
> + .irq_mask_ack = mv64x60_mask_low,
> + .irq_unmask = mv64x60_unmask_low,
> };
>
> /*
> * mv64x60_chip_high functions
> */
>
> -static void mv64x60_mask_high(unsigned int virq)
> +static void mv64x60_mask_high(struct irq_data *d)
> {
> - int level2 = irq_map[virq].hwirq & MV64x60_LEVEL2_MASK;
> + int level2 = irq_map[d->irq].hwirq & MV64x60_LEVEL2_MASK;
> unsigned long flags;
>
> spin_lock_irqsave(&mv64x60_lock, flags);
> @@ -126,9 +126,9 @@ static void mv64x60_mask_high(unsigned int virq)
> (void)in_le32(mv64x60_irq_reg_base + MV64X60_IC_CPU0_INTR_MASK_HI);
> }
>
> -static void mv64x60_unmask_high(unsigned int virq)
> +static void mv64x60_unmask_high(struct irq_data *d)
> {
> - int level2 = irq_map[virq].hwirq & MV64x60_LEVEL2_MASK;
> + int level2 = irq_map[d->irq].hwirq & MV64x60_LEVEL2_MASK;
> unsigned long flags;
>
> spin_lock_irqsave(&mv64x60_lock, flags);
> @@ -141,18 +141,18 @@ static void mv64x60_unmask_high(unsigned int virq)
>
> static struct irq_chip mv64x60_chip_high = {
> .name = "mv64x60_high",
> - .mask = mv64x60_mask_high,
> - .mask_ack = mv64x60_mask_high,
> - .unmask = mv64x60_unmask_high,
> + .irq_mask = mv64x60_mask_high,
> + .irq_mask_ack = mv64x60_mask_high,
> + .irq_unmask = mv64x60_unmask_high,
> };
>
> /*
> * mv64x60_chip_gpp functions
> */
>
> -static void mv64x60_mask_gpp(unsigned int virq)
> +static void mv64x60_mask_gpp(struct irq_data *d)
> {
> - int level2 = irq_map[virq].hwirq & MV64x60_LEVEL2_MASK;
> + int level2 = irq_map[d->irq].hwirq & MV64x60_LEVEL2_MASK;
> unsigned long flags;
>
> spin_lock_irqsave(&mv64x60_lock, flags);
> @@ -163,9 +163,9 @@ static void mv64x60_mask_gpp(unsigned int virq)
> (void)in_le32(mv64x60_gpp_reg_base + MV64x60_GPP_INTR_MASK);
> }
>
> -static void mv64x60_mask_ack_gpp(unsigned int virq)
> +static void mv64x60_mask_ack_gpp(struct irq_data *d)
> {
> - int level2 = irq_map[virq].hwirq & MV64x60_LEVEL2_MASK;
> + int level2 = irq_map[d->irq].hwirq & MV64x60_LEVEL2_MASK;
> unsigned long flags;
>
> spin_lock_irqsave(&mv64x60_lock, flags);
> @@ -178,9 +178,9 @@ static void mv64x60_mask_ack_gpp(unsigned int virq)
> (void)in_le32(mv64x60_gpp_reg_base + MV64x60_GPP_INTR_CAUSE);
> }
>
> -static void mv64x60_unmask_gpp(unsigned int virq)
> +static void mv64x60_unmask_gpp(struct irq_data *d)
> {
> - int level2 = irq_map[virq].hwirq & MV64x60_LEVEL2_MASK;
> + int level2 = irq_map[d->irq].hwirq & MV64x60_LEVEL2_MASK;
> unsigned long flags;
>
> spin_lock_irqsave(&mv64x60_lock, flags);
> @@ -193,9 +193,9 @@ static void mv64x60_unmask_gpp(unsigned int virq)
>
> static struct irq_chip mv64x60_chip_gpp = {
> .name = "mv64x60_gpp",
> - .mask = mv64x60_mask_gpp,
> - .mask_ack = mv64x60_mask_ack_gpp,
> - .unmask = mv64x60_unmask_gpp,
> + .irq_mask = mv64x60_mask_gpp,
> + .irq_mask_ack = mv64x60_mask_ack_gpp,
> + .irq_unmask = mv64x60_unmask_gpp,
> };
>
> /*
> diff --git a/arch/powerpc/sysdev/qe_lib/qe_ic.c b/arch/powerpc/sysdev/qe_lib/qe_ic.c
> index 541ba98..24bfc1e 100644
> --- a/arch/powerpc/sysdev/qe_lib/qe_ic.c
> +++ b/arch/powerpc/sysdev/qe_lib/qe_ic.c
> @@ -189,15 +189,15 @@ static inline void qe_ic_write(volatile __be32 __iomem * base, unsigned int reg
>
> static inline struct qe_ic *qe_ic_from_irq(unsigned int virq)
> {
> - return irq_to_desc(virq)->chip_data;
> + return get_irq_chip_data(virq);
> }
>
> #define virq_to_hw(virq) ((unsigned int)irq_map[virq].hwirq)
>
> -static void qe_ic_unmask_irq(unsigned int virq)
> +static void qe_ic_unmask_irq(struct irq_data *d)
> {
> - struct qe_ic *qe_ic = qe_ic_from_irq(virq);
> - unsigned int src = virq_to_hw(virq);
> + struct qe_ic *qe_ic = qe_ic_from_irq(d->irq);
> + unsigned int src = virq_to_hw(d->irq);
> unsigned long flags;
> u32 temp;
>
> @@ -210,10 +210,10 @@ static void qe_ic_unmask_irq(unsigned int virq)
> raw_spin_unlock_irqrestore(&qe_ic_lock, flags);
> }
>
> -static void qe_ic_mask_irq(unsigned int virq)
> +static void qe_ic_mask_irq(struct irq_data *d)
> {
> - struct qe_ic *qe_ic = qe_ic_from_irq(virq);
> - unsigned int src = virq_to_hw(virq);
> + struct qe_ic *qe_ic = qe_ic_from_irq(d->irq);
> + unsigned int src = virq_to_hw(d->irq);
> unsigned long flags;
> u32 temp;
>
> @@ -238,9 +238,9 @@ static void qe_ic_mask_irq(unsigned int virq)
>
> static struct irq_chip qe_ic_irq_chip = {
> .name = "QEIC",
> - .unmask = qe_ic_unmask_irq,
> - .mask = qe_ic_mask_irq,
> - .mask_ack = qe_ic_mask_irq,
> + .irq_unmask = qe_ic_unmask_irq,
> + .irq_mask = qe_ic_mask_irq,
> + .irq_mask_ack = qe_ic_mask_irq,
> };
>
> static int qe_ic_host_match(struct irq_host *h, struct device_node *node)
> diff --git a/arch/powerpc/sysdev/tsi108_pci.c b/arch/powerpc/sysdev/tsi108_pci.c
> index 0ab9281..02c91db 100644
> --- a/arch/powerpc/sysdev/tsi108_pci.c
> +++ b/arch/powerpc/sysdev/tsi108_pci.c
> @@ -343,24 +343,9 @@ static inline unsigned int get_pci_source(void)
> * Linux descriptor level callbacks
> */
>
> -static void tsi108_pci_irq_enable(u_int irq)
> +static void tsi108_pci_irq_unmask(struct irq_data *d)
> {
> - tsi108_pci_int_unmask(irq);
> -}
> -
> -static void tsi108_pci_irq_disable(u_int irq)
> -{
> - tsi108_pci_int_mask(irq);
> -}
> -
> -static void tsi108_pci_irq_ack(u_int irq)
> -{
> - tsi108_pci_int_mask(irq);
> -}
> -
> -static void tsi108_pci_irq_end(u_int irq)
> -{
> - tsi108_pci_int_unmask(irq);
> + tsi108_pci_int_unmask(d->irq);
>
> /* Enable interrupts from PCI block */
> tsi108_write_reg(TSI108_PCI_OFFSET + TSI108_PCI_IRP_ENABLE,
> @@ -370,16 +355,25 @@ static void tsi108_pci_irq_end(u_int irq)
> mb();
> }
>
> +static void tsi108_pci_irq_mask(struct irq_data *d)
> +{
> + tsi108_pci_int_mask(d->irq);
> +}
> +
> +static void tsi108_pci_irq_ack(struct irq_data *d)
> +{
> + tsi108_pci_int_mask(d->irq);
> +}
> +
> /*
> * Interrupt controller descriptor for cascaded PCI interrupt controller.
> */
>
> static struct irq_chip tsi108_pci_irq = {
> .name = "tsi108_PCI_int",
> - .mask = tsi108_pci_irq_disable,
> - .ack = tsi108_pci_irq_ack,
> - .end = tsi108_pci_irq_end,
> - .unmask = tsi108_pci_irq_enable,
> + .irq_mask = tsi108_pci_irq_mask,
> + .irq_ack = tsi108_pci_irq_ack,
> + .irq_unmask = tsi108_pci_irq_unmask,
> };
>
> static int pci_irq_host_xlate(struct irq_host *h, struct device_node *ct,
> @@ -437,8 +431,11 @@ void __init tsi108_pci_int_init(struct device_node *node)
>
> void tsi108_irq_cascade(unsigned int irq, struct irq_desc *desc)
> {
> + struct irq_chip *chip = get_irq_desc_chip(desc);
> unsigned int cascade_irq = get_pci_source();
> +
> if (cascade_irq != NO_IRQ)
> generic_handle_irq(cascade_irq);
> - desc->chip->eoi(irq);
> +
> + chip->irq_eoi(&desc->irq_data);
> }
> diff --git a/arch/powerpc/sysdev/uic.c b/arch/powerpc/sysdev/uic.c
> index 0038fb7..1fb46fe 100644
> --- a/arch/powerpc/sysdev/uic.c
> +++ b/arch/powerpc/sysdev/uic.c
> @@ -55,11 +55,11 @@ struct uic {
> struct irq_host *irqhost;
> };
>
> -static void uic_unmask_irq(unsigned int virq)
> +static void uic_unmask_irq(struct irq_data *d)
> {
> - struct irq_desc *desc = irq_to_desc(virq);
> - struct uic *uic = get_irq_chip_data(virq);
> - unsigned int src = uic_irq_to_hw(virq);
> + struct irq_desc *desc = irq_to_desc(d->irq);
> + struct uic *uic = get_irq_chip_data(d->irq);
> + unsigned int src = uic_irq_to_hw(d->irq);
> unsigned long flags;
> u32 er, sr;
>
> @@ -74,10 +74,10 @@ static void uic_unmask_irq(unsigned int virq)
> spin_unlock_irqrestore(&uic->lock, flags);
> }
>
> -static void uic_mask_irq(unsigned int virq)
> +static void uic_mask_irq(struct irq_data *d)
> {
> - struct uic *uic = get_irq_chip_data(virq);
> - unsigned int src = uic_irq_to_hw(virq);
> + struct uic *uic = get_irq_chip_data(d->irq);
> + unsigned int src = uic_irq_to_hw(d->irq);
> unsigned long flags;
> u32 er;
>
> @@ -88,10 +88,10 @@ static void uic_mask_irq(unsigned int virq)
> spin_unlock_irqrestore(&uic->lock, flags);
> }
>
> -static void uic_ack_irq(unsigned int virq)
> +static void uic_ack_irq(struct irq_data *d)
> {
> - struct uic *uic = get_irq_chip_data(virq);
> - unsigned int src = uic_irq_to_hw(virq);
> + struct uic *uic = get_irq_chip_data(d->irq);
> + unsigned int src = uic_irq_to_hw(d->irq);
> unsigned long flags;
>
> spin_lock_irqsave(&uic->lock, flags);
> @@ -99,11 +99,11 @@ static void uic_ack_irq(unsigned int virq)
> spin_unlock_irqrestore(&uic->lock, flags);
> }
>
> -static void uic_mask_ack_irq(unsigned int virq)
> +static void uic_mask_ack_irq(struct irq_data *d)
> {
> - struct irq_desc *desc = irq_to_desc(virq);
> - struct uic *uic = get_irq_chip_data(virq);
> - unsigned int src = uic_irq_to_hw(virq);
> + struct irq_desc *desc = irq_to_desc(d->irq);
> + struct uic *uic = get_irq_chip_data(d->irq);
> + unsigned int src = uic_irq_to_hw(d->irq);
> unsigned long flags;
> u32 er, sr;
>
> @@ -125,18 +125,18 @@ static void uic_mask_ack_irq(unsigned int virq)
> spin_unlock_irqrestore(&uic->lock, flags);
> }
>
> -static int uic_set_irq_type(unsigned int virq, unsigned int flow_type)
> +static int uic_set_irq_type(struct irq_data *d, unsigned int flow_type)
> {
> - struct uic *uic = get_irq_chip_data(virq);
> - unsigned int src = uic_irq_to_hw(virq);
> - struct irq_desc *desc = irq_to_desc(virq);
> + struct uic *uic = get_irq_chip_data(d->irq);
> + unsigned int src = uic_irq_to_hw(d->irq);
> + struct irq_desc *desc = irq_to_desc(d->irq);
> unsigned long flags;
> int trigger, polarity;
> u32 tr, pr, mask;
>
> switch (flow_type & IRQ_TYPE_SENSE_MASK) {
> case IRQ_TYPE_NONE:
> - uic_mask_irq(virq);
> + uic_mask_irq(d);
> return 0;
>
> case IRQ_TYPE_EDGE_RISING:
> @@ -178,11 +178,11 @@ static int uic_set_irq_type(unsigned int virq, unsigned int flow_type)
>
> static struct irq_chip uic_irq_chip = {
> .name = "UIC",
> - .unmask = uic_unmask_irq,
> - .mask = uic_mask_irq,
> - .mask_ack = uic_mask_ack_irq,
> - .ack = uic_ack_irq,
> - .set_type = uic_set_irq_type,
> + .irq_unmask = uic_unmask_irq,
> + .irq_mask = uic_mask_irq,
> + .irq_mask_ack = uic_mask_ack_irq,
> + .irq_ack = uic_ack_irq,
> + .irq_set_type = uic_set_irq_type,
> };
>
> static int uic_host_map(struct irq_host *h, unsigned int virq,
> @@ -220,6 +220,7 @@ static struct irq_host_ops uic_host_ops = {
>
> void uic_irq_cascade(unsigned int virq, struct irq_desc *desc)
> {
> + struct irq_chip *chip = get_irq_desc_chip(desc);
> struct uic *uic = get_irq_data(virq);
> u32 msr;
> int src;
> @@ -227,9 +228,9 @@ void uic_irq_cascade(unsigned int virq, struct irq_desc *desc)
>
> raw_spin_lock(&desc->lock);
> if (desc->status & IRQ_LEVEL)
> - desc->chip->mask(virq);
> + chip->irq_mask(&desc->irq_data);
> else
> - desc->chip->mask_ack(virq);
> + chip->irq_mask_ack(&desc->irq_data);
> raw_spin_unlock(&desc->lock);
>
> msr = mfdcr(uic->dcrbase + UIC_MSR);
> @@ -244,9 +245,9 @@ void uic_irq_cascade(unsigned int virq, struct irq_desc *desc)
> uic_irq_ret:
> raw_spin_lock(&desc->lock);
> if (desc->status & IRQ_LEVEL)
> - desc->chip->ack(virq);
> - if (!(desc->status & IRQ_DISABLED) && desc->chip->unmask)
> - desc->chip->unmask(virq);
> + chip->irq_ack(&desc->irq_data);
> + if (!(desc->status & IRQ_DISABLED) && chip->irq_unmask)
> + chip->irq_unmask(&desc->irq_data);
> raw_spin_unlock(&desc->lock);
> }
>
> diff --git a/arch/powerpc/sysdev/xilinx_intc.c b/arch/powerpc/sysdev/xilinx_intc.c
> index 1e0ccfa..0512f58 100644
> --- a/arch/powerpc/sysdev/xilinx_intc.c
> +++ b/arch/powerpc/sysdev/xilinx_intc.c
> @@ -69,17 +69,17 @@ static unsigned char xilinx_intc_map_senses[] = {
> *
> * IRQ Chip common (across level and edge) operations
> */
> -static void xilinx_intc_mask(unsigned int virq)
> +static void xilinx_intc_mask(struct irq_data *d)
> {
> - int irq = virq_to_hw(virq);
> - void * regs = get_irq_chip_data(virq);
> + int irq = virq_to_hw(d->irq);
> + void * regs = get_irq_chip_data(d->irq);
> pr_debug("mask: %d\n", irq);
> out_be32(regs + XINTC_CIE, 1 << irq);
> }
>
> -static int xilinx_intc_set_type(unsigned int virq, unsigned int flow_type)
> +static int xilinx_intc_set_type(struct irq_data *d, unsigned int flow_type)
> {
> - struct irq_desc *desc = irq_to_desc(virq);
> + struct irq_desc *desc = irq_to_desc(d->irq);
>
> desc->status &= ~(IRQ_TYPE_SENSE_MASK | IRQ_LEVEL);
> desc->status |= flow_type & IRQ_TYPE_SENSE_MASK;
> @@ -91,10 +91,10 @@ static int xilinx_intc_set_type(unsigned int virq, unsigned int flow_type)
> /*
> * IRQ Chip level operations
> */
> -static void xilinx_intc_level_unmask(unsigned int virq)
> +static void xilinx_intc_level_unmask(struct irq_data *d)
> {
> - int irq = virq_to_hw(virq);
> - void * regs = get_irq_chip_data(virq);
> + int irq = virq_to_hw(d->irq);
> + void * regs = get_irq_chip_data(d->irq);
> pr_debug("unmask: %d\n", irq);
> out_be32(regs + XINTC_SIE, 1 << irq);
>
> @@ -107,37 +107,37 @@ static void xilinx_intc_level_unmask(unsigned int virq)
>
> static struct irq_chip xilinx_intc_level_irqchip = {
> .name = "Xilinx Level INTC",
> - .mask = xilinx_intc_mask,
> - .mask_ack = xilinx_intc_mask,
> - .unmask = xilinx_intc_level_unmask,
> - .set_type = xilinx_intc_set_type,
> + .irq_mask = xilinx_intc_mask,
> + .irq_mask_ack = xilinx_intc_mask,
> + .irq_unmask = xilinx_intc_level_unmask,
> + .irq_set_type = xilinx_intc_set_type,
> };
>
> /*
> * IRQ Chip edge operations
> */
> -static void xilinx_intc_edge_unmask(unsigned int virq)
> +static void xilinx_intc_edge_unmask(struct irq_data *d)
> {
> - int irq = virq_to_hw(virq);
> - void *regs = get_irq_chip_data(virq);
> + int irq = virq_to_hw(d->irq);
> + void *regs = get_irq_chip_data(d->irq);
> pr_debug("unmask: %d\n", irq);
> out_be32(regs + XINTC_SIE, 1 << irq);
> }
>
> -static void xilinx_intc_edge_ack(unsigned int virq)
> +static void xilinx_intc_edge_ack(struct irq_data *d)
> {
> - int irq = virq_to_hw(virq);
> - void * regs = get_irq_chip_data(virq);
> + int irq = virq_to_hw(d->irq);
> + void * regs = get_irq_chip_data(d->irq);
> pr_debug("ack: %d\n", irq);
> out_be32(regs + XINTC_IAR, 1 << irq);
> }
>
> static struct irq_chip xilinx_intc_edge_irqchip = {
> .name = "Xilinx Edge INTC",
> - .mask = xilinx_intc_mask,
> - .unmask = xilinx_intc_edge_unmask,
> - .ack = xilinx_intc_edge_ack,
> - .set_type = xilinx_intc_set_type,
> + .irq_mask = xilinx_intc_mask,
> + .irq_unmask = xilinx_intc_edge_unmask,
> + .irq_ack = xilinx_intc_edge_ack,
> + .irq_set_type = xilinx_intc_set_type,
> };
>
> /*
> @@ -229,12 +229,14 @@ int xilinx_intc_get_irq(void)
> */
> static void xilinx_i8259_cascade(unsigned int irq, struct irq_desc *desc)
> {
> + struct irq_chip *chip = get_irq_desc_chip(desc);
> unsigned int cascade_irq = i8259_irq();
> +
> if (cascade_irq)
> generic_handle_irq(cascade_irq);
>
> /* Let xilinx_intc end the interrupt */
> - desc->chip->unmask(irq);
> + chip->irq_unmask(&desc->irq_data);
> }
>
> static void __init xilinx_i8259_setup_cascade(void)
> --
> 1.7.1
^ permalink raw reply
* Re: [RFC] Inter-processor Mailboxes Drivers
From: Blanchard, Hollis @ 2011-02-14 23:05 UTC (permalink / raw)
To: Linus Walleij
Cc: Inge, Meador, openmcapi-dev, Hiroshi DOYU, linuxppc-dev,
linux-arm-kernel
In-Reply-To: <AANLkTin+ZSNHX2iv=XwWCgxy330UJwhkf1T=4BMXZ22s@mail.gmail.com>
On 02/13/2011 01:24 PM, Linus Walleij wrote:
>> > 3. Userspace interfaces for accessing the mailboxes. A
>> > '/dev/mailbox1', '/dev/mailbox2', etc... mapping, for =
example.
> What kind of business does userspace have with directly using
> mailboxes? Enlighten me so I get it... in our system these are
> used by protocols, such as net/caif/* thru drivers/net/caif/*, and
> we have similar kernelspace functionality for Phonet.
>
> CAIF and Phonet on the other hand, have custom openings
> down to the thing that exists on the other end of the mailbox.
> Most of these systems tend to talk some funny protocol that
> is often better handled by the kernel than by any userspace.
>
> So is this for the situation when you have no intermediate
> protocol between your userpace and the other CPU's
> subsystem? Or are you thinking about handling that
> protocol in userspace? That is generally not such a good idea
> for efficiency reasons.
OpenMCAPI (http://openmcapi.org) implements the MCAPI specification,=20
which is a simple application-level communication API that uses shared=20
memory. The API could be layered over any protocol, but was more or less =
designed for simple shared-memory systems, e.g. fixed topology, no=20
retransmission, etc.
Currently, we implement almost all of this as a shared library, plus a=20
very small kernel driver. The only requirements on the kernel are to=20
allow userspace to map the shared memory area, and provide an IPI=20
mechanism (and allow the process to sleep while waiting). Applications=20
sync with each other using normal atomic memory operations.
We're now trying to optimize the transfer of scalars on platforms that=20
provide mailboxes (beyond simple IPIs), which is why we're looking at=20
defining a user-facing API to such hardware.
I'll add that we haven't done serious optimization yet, but the numbers=20
we do have seem reasonable. What are the "efficiency" issues you're=20
worried about?
Hollis Blanchard
Mentor Graphics, Embedded Systems Division
^ 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