* Re: 85xx Address space query
From: kernel mailz @ 2009-06-25 10:51 UTC (permalink / raw)
To: Scott Wood; +Cc: linuxppc-dev
In-Reply-To: <4A42AE1A.1090107@freescale.com>
So this means
when kernel gets interrupted by app which may be in PID=5 (say)
kernel translations for PID=0 remain valid ?
I am not able to follow Scott
-TZ
On Thu, Jun 25, 2009 at 4:22 AM, Scott Wood<scottwood@freescale.com> wrote:
> kernel mailz wrote:
>>
>> But If the app was running with PID=1, interrupt occurs, kernel code
>> gets executed in PID=1, how does the kernel handle this ? and goes
>> back to PID=0, since its translations are all in PID=0
>
> PID 0 is special, it's mappings are present regardless of the value of the
> PID register.
>
> -Scott
>
^ permalink raw reply
* Re: [PATCH] ucc_geth: Fix half-duplex operation for non-MII/RMII interfaces
From: Anton Vorontsov @ 2009-06-25 11:17 UTC (permalink / raw)
To: Mark Huth; +Cc: linuxppc-dev, netdev, Li Yang, David Miller
In-Reply-To: <20090625070236.GA27711@oksana.dev.rtsoft.ru>
On Thu, Jun 25, 2009 at 11:02:36AM +0400, Anton Vorontsov wrote:
[...]
> Of course, it could be that the root cause of the problems
> I observe is weird NIC on my host. Well, then QA team should
> have used the same broken NIC on their hosts. :-)
>
> I can easily test it by interconnecting two targets though.
[...]
> Definitely. Though I'm out of ideas if it's NOT host-side issue.
Two boards interconnected work fine. eTSEC + SKY2 NIC also work
OK. I'll test some more NICs, known to not work is 3Com
Corporation 3c905C-TX/TX-M [Tornado] (rev 74).
After some netperf tests, statistic on a gianfar board:
# ethtool -S eth0 | grep -v ": 0"
NIC statistics:
rx-dropped-by-kernel: 2
tx-rx-64-frames: 52
tx-rx-65-127-frames: 20668
tx-rx-128-255-frames: 10343
tx-rx-256-511-frames: 113
tx-rx-512-1023-frames: 147
tx-rx-1024-1518-frames: 45965
rx-bytes: 45075782
rx-packets: 50300
rx-carrier-sense-error: 1
rx-fragmented-frames: 7600
tx-byte-counter: 27401677
tx-packets: 34618
tx-broadcast-packets: 3
tx-deferral-packets: 5
tx-single-collision-packets: 4039
tx-multiple-collision-packets: 1943
tx-excessive-collision-packets: 30
tx-total-collision: 785
Thanks for the ideas, Mark.
--
Anton Vorontsov
email: cbouatmailru@gmail.com
irc://irc.freenode.net/bd2
^ permalink raw reply
* Re: [PATCH v2] Fix RTAS watchdog driver temperature read functionality
From: Utz Bacher @ 2009-06-25 11:22 UTC (permalink / raw)
To: Adrian Reber; +Cc: linuxppc-dev-bounces+adrian=lisas.de, linuxppc-dev
In-Reply-To: <20090611105216.GG8358@lisas.de>
[-- Attachment #1: Type: text/plain, Size: 1836 bytes --]
Adrian Reber wrote on 11.06.2009 12:52:17:
>
> I forgot about this patch. Can this still be merged?
>
>
> On Thu, Mar 26, 2009 at 01:05:42PM +0100, Adrian Reber wrote:
> > Using the RTAS watchdog driver to read out the temperature crashes
> > on a PXCAB:
> >
> > Unable to handle kernel paging request for data at address 0xfe347b50
> > Faulting instruction address: 0xc00000000001af64
> > Oops: Kernel access of bad area, sig: 11 [#1]
> >
> > The wrong usage of "(void *)__pa(&temperature)" in rtas_call() is
> > removed by using the function rtas_get_sensor() which does the
> > right thing.
> >
> > Signed-off-by: Adrian Reber <adrian@lisas.de>
> > ---
> > v2: use rtas_get_sensor(); typo fixed
> > ---
> > drivers/watchdog/wdrtas.c | 8 +++-----
> > 1 files changed, 3 insertions(+), 5 deletions(-)
> >
> > diff --git a/drivers/watchdog/wdrtas.c b/drivers/watchdog/wdrtas.c
> > index 5d3b1a8..a9f00dc 100644
> > --- a/drivers/watchdog/wdrtas.c
> > +++ b/drivers/watchdog/wdrtas.c
> > @@ -214,16 +214,14 @@ static void wdrtas_timer_keepalive(void)
> > */
> > static int wdrtas_get_temperature(void)
> > {
> > - long result;
> > + int result;
> > int temperature = 0;
> >
> > - result = rtas_call(wdrtas_token_get_sensor_state, 2, 2,
> > - (void *)__pa(&temperature),
> > - WDRTAS_THERMAL_SENSOR, 0);
> > + result = rtas_get_sensor(WDRTAS_THERMAL_SENSOR, 0, &temperature);
> >
> > if (result < 0)
> > printk(KERN_WARNING "wdrtas: reading the thermal sensor "
> > - "faild: %li\n", result);
> > + "failed: %i\n", result);
> > else
> > temperature = ((temperature * 9) / 5) + 32; /* fahrenheit */
> >
> > --
> > 1.5.6.6
makes sense. Second version also looks good to me -- thanks!
Acked-by: Utz Bacher <utz.bacher@de.ibm.com>
Utz
:wq
[-- Attachment #2: Type: text/html, Size: 2852 bytes --]
^ permalink raw reply
* Re: [PATCH v2] Fix RTAS watchdog driver temperature read functionality
From: Benjamin Herrenschmidt @ 2009-06-25 11:28 UTC (permalink / raw)
To: Utz Bacher; +Cc: linuxppc-dev
In-Reply-To: <OF3E26F577.90C4A946-ONC12575E0.003E09AB-C12575E0.003E67E9@de.ibm.com>
On Thu, 2009-06-25 at 13:22 +0200, Utz Bacher wrote:
>
> Adrian Reber wrote on 11.06.2009 12:52:17:
> >
> > I forgot about this patch. Can this still be merged?
Probably, can you re-send it in proper format to the list so it gets
into patchwork (unless it's already there in which case I'll pick it up
anyway) ?
Cheers,
Ben.
> >
> > On Thu, Mar 26, 2009 at 01:05:42PM +0100, Adrian Reber wrote:
> > > Using the RTAS watchdog driver to read out the temperature crashes
> > > on a PXCAB:
> > >
> > > Unable to handle kernel paging request for data at address
> 0xfe347b50
> > > Faulting instruction address: 0xc00000000001af64
> > > Oops: Kernel access of bad area, sig: 11 [#1]
> > >
> > > The wrong usage of "(void *)__pa(&temperature)" in rtas_call() is
> > > removed by using the function rtas_get_sensor() which does the
> > > right thing.
> > >
> > > Signed-off-by: Adrian Reber <adrian@lisas.de>
> > > ---
> > > v2: use rtas_get_sensor(); typo fixed
> > > ---
> > > drivers/watchdog/wdrtas.c | 8 +++-----
> > > 1 files changed, 3 insertions(+), 5 deletions(-)
> > >
> > > diff --git a/drivers/watchdog/wdrtas.c b/drivers/watchdog/wdrtas.c
> > > index 5d3b1a8..a9f00dc 100644
> > > --- a/drivers/watchdog/wdrtas.c
> > > +++ b/drivers/watchdog/wdrtas.c
> > > @@ -214,16 +214,14 @@ static void wdrtas_timer_keepalive(void)
> > > */
> > > static int wdrtas_get_temperature(void)
> > > {
> > > - long result;
> > > + int result;
> > > int temperature = 0;
> > >
> > > - result = rtas_call(wdrtas_token_get_sensor_state, 2, 2,
> > > - (void *)__pa(&temperature),
> > > - WDRTAS_THERMAL_SENSOR, 0);
> > > + result = rtas_get_sensor(WDRTAS_THERMAL_SENSOR, 0,
> &temperature);
> > >
> > > if (result < 0)
> > > printk(KERN_WARNING "wdrtas: reading the thermal sensor "
> > > - "faild: %li\n", result);
> > > + "failed: %i\n", result);
> > > else
> > > temperature = ((temperature * 9) / 5) + 32; /* fahrenheit
> */
> > >
> > > --
> > > 1.5.6.6
>
> makes sense. Second version also looks good to me -- thanks!
>
> Acked-by: Utz Bacher <utz.bacher@de.ibm.com>
>
> Utz
>
> :wq
^ permalink raw reply
* Re: 85xx Address space query
From: Benjamin Herrenschmidt @ 2009-06-25 11:32 UTC (permalink / raw)
To: Kumar Gala; +Cc: linuxppc-dev, kernel mailz
In-Reply-To: <D47FC871-1535-4DBF-8617-6EEA8C180484@kernel.crashing.org>
> > 1. User code executes ioctl
> > 2. interrupt goes to the kernel
>
> On the interrupt the PR changes from 0 -> 1
The other way around actually :-)
> > 3. ioctl handler in driver gets invoked
> > The buffer pointer still contains 0x10000.
> >
> > How kernel code running in PR=0 accesses it and does the copy. I am
> > not able to see a address space switch in the asm code of
> > copy_tofrom_user.
>
> There isn't a address space switch. But address spaces exist at the
> same time. The user app is given 0..0xc000_0000 and the kernel uses
> 0xc000_0000..0xffff_ffff.
You may want to add, to make things clearer, that the HW treats PID 0
specially. Translations in the TLB that have PID (we call it TID in the
TLB entry) 0 match any value of the PID register.
So kernel pages all have TID = 0, which means they are visible to all
processes, but have permissions set such that only the supervisor (ie.
PR = 0) can actually access them. MSR:PR is automatically switched to 0
by the processor when taking an interrupt, allowing the kernel thus to
access both its own pages and the pages of the current process.
Cheers,
Ben.
^ permalink raw reply
* Re: 85xx Address space query
From: Benjamin Herrenschmidt @ 2009-06-25 11:33 UTC (permalink / raw)
To: kernel mailz; +Cc: linuxppc-dev
In-Reply-To: <abe8a1fd0906241046x2e3ee7d5h6a6c0231086a6f0e@mail.gmail.com>
On Wed, 2009-06-24 at 23:16 +0530, kernel mailz wrote:
> But If the app was running with PID=1, interrupt occurs, kernel code
> gets executed in PID=1, how does the kernel handle this ? and goes
> back to PID=0, since its translations are all in PID=0
PID 0 is a special case in HW. TLB entries with TID=0 will match any PID
value.
Cheers,
Ben.
^ permalink raw reply
* Direct MII connection between MPC8313 and VIRTEX FPGA
From: Frank Prepelica @ 2009-06-25 15:11 UTC (permalink / raw)
To: linuxppc-dev
Hi all,
we removed the ethernet PHYs (MARVELL) from our customized board (based =
on MPC8313ERDB) and=20
connected the CPU Ethernet lines directly to a FPGA which is now =
emulating the PHY. But the ifconfig=20
command cannot find that eth device anymore. Does the emulated PHY needs =
to provide MDIO=20
information that the ETH device can be found again?
Any help is very appreciated
Best regards
Frank
Frank Prepelica
Software Design Engineer
Ubidyne GmbH
Lise-Meitner-Str.-14
89081 Ulm - Germany
Phone:=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 +49 731 88 00 71 58
Fax:=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 +49 731 88 00 71 99
Email:=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 =
frank.prepelica@ubidyne.com
Homepage:=A0=A0=A0=A0=A0=A0 www.ubidyne.com
=A0
Registered office: Ulm
District court of Ulm: HRB 5295
Managing Directors:
Dipl. Ing. Ken Hawk
Dipl. Ing. Beat M=FCller
Dipl. Ing. Mike Levis
^ permalink raw reply
* Re: 85xx Address space query
From: Kumar Gala @ 2009-06-25 17:32 UTC (permalink / raw)
To: kernel mailz; +Cc: Scott Wood, linuxppc-dev
In-Reply-To: <abe8a1fd0906250351y1aadc153m9f52f65a5860a2ca@mail.gmail.com>
That is correct. The PID = 0 translations are always valid.
- k
On Jun 25, 2009, at 5:51 AM, kernel mailz wrote:
> So this means
> when kernel gets interrupted by app which may be in PID=5 (say)
> kernel translations for PID=0 remain valid ?
> I am not able to follow Scott
>
> -TZ
>
> On Thu, Jun 25, 2009 at 4:22 AM, Scott Wood<scottwood@freescale.com>
> wrote:
>> kernel mailz wrote:
>>>
>>> But If the app was running with PID=1, interrupt occurs, kernel code
>>> gets executed in PID=1, how does the kernel handle this ? and goes
>>> back to PID=0, since its translations are all in PID=0
>>
>> PID 0 is special, it's mappings are present regardless of the value
>> of the
>> PID register.
>>
>> -Scott
>>
> _______________________________________________
> Linuxppc-dev mailing list
> Linuxppc-dev@lists.ozlabs.org
> https://lists.ozlabs.org/listinfo/linuxppc-dev
^ permalink raw reply
* Re: 85xx Address space query
From: kernel mailz @ 2009-06-25 17:52 UTC (permalink / raw)
To: Kumar Gala; +Cc: Scott Wood, linuxppc-dev
In-Reply-To: <4FA3B563-2881-4F9E-8B23-C36FB439BE2B@kernel.crashing.org>
If an aap has to be placed in AS=1 and it issues an ioctl, kernel
needs to be modified ?
I guess the PID=0 trick will work when AS is same
right ?
On 6/25/09, Kumar Gala <galak@kernel.crashing.org> wrote:
> That is correct. The PID = 0 translations are always valid.
>
> - k
>
> On Jun 25, 2009, at 5:51 AM, kernel mailz wrote:
>
>> So this means
>> when kernel gets interrupted by app which may be in PID=5 (say)
>> kernel translations for PID=0 remain valid ?
>> I am not able to follow Scott
>>
>> -TZ
>>
>> On Thu, Jun 25, 2009 at 4:22 AM, Scott Wood<scottwood@freescale.com>
>> wrote:
>>> kernel mailz wrote:
>>>>
>>>> But If the app was running with PID=1, interrupt occurs, kernel code
>>>> gets executed in PID=1, how does the kernel handle this ? and goes
>>>> back to PID=0, since its translations are all in PID=0
>>>
>>> PID 0 is special, it's mappings are present regardless of the value
>>> of the
>>> PID register.
>>>
>>> -Scott
>>>
>> _______________________________________________
>> Linuxppc-dev mailing list
>> Linuxppc-dev@lists.ozlabs.org
>> https://lists.ozlabs.org/listinfo/linuxppc-dev
>
>
^ permalink raw reply
* Re: 85xx Address space query
From: Kumar Gala @ 2009-06-25 17:58 UTC (permalink / raw)
To: kernel mailz; +Cc: Scott Wood, linuxppc-dev
In-Reply-To: <abe8a1fd0906251052k22ceabfcr378133af61d2ff71@mail.gmail.com>
On Jun 25, 2009, at 12:52 PM, kernel mailz wrote:
> If an aap has to be placed in AS=1 and it issues an ioctl, kernel
> needs to be modified ?
Correct, this would be a significant change to the kernel.
> I guess the PID=0 trick will work when AS is same
>
> right ?
correct.
- k
>
> On 6/25/09, Kumar Gala <galak@kernel.crashing.org> wrote:
>> That is correct. The PID = 0 translations are always valid.
>>
>> - k
>>
>> On Jun 25, 2009, at 5:51 AM, kernel mailz wrote:
>>
>>> So this means
>>> when kernel gets interrupted by app which may be in PID=5 (say)
>>> kernel translations for PID=0 remain valid ?
>>> I am not able to follow Scott
>>>
>>> -TZ
>>>
>>> On Thu, Jun 25, 2009 at 4:22 AM, Scott Wood<scottwood@freescale.com>
>>> wrote:
>>>> kernel mailz wrote:
>>>>>
>>>>> But If the app was running with PID=1, interrupt occurs, kernel
>>>>> code
>>>>> gets executed in PID=1, how does the kernel handle this ? and goes
>>>>> back to PID=0, since its translations are all in PID=0
>>>>
>>>> PID 0 is special, it's mappings are present regardless of the value
>>>> of the
>>>> PID register.
>>>>
>>>> -Scott
>>>>
>>> _______________________________________________
>>> Linuxppc-dev mailing list
>>> Linuxppc-dev@lists.ozlabs.org
>>> https://lists.ozlabs.org/listinfo/linuxppc-dev
>>
>>
^ permalink raw reply
* Slowing down the schedular, How?
From: kernel mailz @ 2009-06-25 18:38 UTC (permalink / raw)
To: linuxppc-dev
In-Reply-To: <abe8a1fd0906251136t36d78428k90a610fdff987ab6@mail.gmail.com>
Hi,
I have a SMP linux running on 85xx poweprc. Say on Core 0 and Core 1
two different processes are running and on both the schedular runs.
Now for some special case, if one of my process issues a ioctl which
gets serviced by a kernel module, I wish to slow the schedular on that
core only. Otherwise the performance will get degraded.
Should I use highest priority tasklet, will it be sufficient or i need
to do something special
-TZ
^ permalink raw reply
* Re: Subject: [PATCH v6] spi: Add PPC4xx SPI driver
From: Steven A. Falco @ 2009-06-25 18:53 UTC (permalink / raw)
To: David Brownell, Stefan Roese; +Cc: linuxppc-dev@ozlabs.org
In-Reply-To: <200906251833.n5PIX42Z017229@saf.cs.myharris.net>
Stefan suggested that I try to address the comments against the PPC4xx
SPI driver, so here goes...
A post of version 7 of the driver will follow this email, but I thought
it might make it easier on everyone to inline my comments here. Hence,
this brief, introductory "top post".
> On Thursday 08 January 2009, Stefan Roese wrote:
>> This adds a SPI driver for the SPI controller found in the IBM/AMCC
>> 4xx PowerPC's.
>
>
>> +/*
>> + * The PPC4xx SPI controller has no FIFO so each sent/received byte will
>> + * generate an interrupt to the CPU. This can cause high CPU utilization.
>> + * This driver allows platforms to reduce the interrupt load on the CPU
>> + * during SPI transfers by setting max_speed_hz via the device tree.
>
> Note that an alternate strategy is to use polling instead of IRQs,
> at least when the data rate is high enough that the IRQ processing
> is also slowing down the data transfers.
>
>
>> +/* bits in mode register - bit 0 ist MSb */
>> +/* data latched on leading edge of clock, else trailing edge */
>> +#define SPI_PPC4XX_MODE_SCP (0x80 >> 3)
>
> Or in short, SCP == CPHA.
>
Actually, SCP = !CPHA. I've added a comment to that effect in v7.
>> +/* port enabled */
>> +#define SPI_PPC4XX_MODE_SPE (0x80 >> 4)
>> +/* MSB first, else LSB first */
>> +#define SPI_PPC4XX_MODE_RD (0x80 >> 5)
>> +/* clock invert - idle clock = 1, active clock = 0; else reversed */
>> +#define SPI_PPC4XX_MODE_CI (0x80 >> 6)
>
> Or in short, CI == CPOL.
>
Correct. Comment added.
>> +/* loopback enable */
>> +#define SPI_PPC4XX_MODE_IL (0x80 >> 7)
>> +/* bits in control register */
>> +/* starts a transfer when set */
>> +#define SPI_PPC4XX_CR_STR (0x80 >> 7)
>> +/* bits in status register */
>> +/* port is busy with a transfer */
>> +#define SPI_PPC4XX_SR_BSY (0x80 >> 6)
>> +/* RxD ready */
>> +#define SPI_PPC4XX_SR_RBR (0x80 >> 7)
>> +
>> +/* the spi->mode bits understood by this driver: */
>> +#define MODEBITS (SPI_CPHA | SPI_CPOL | SPI_CS_HIGH | SPI_LSB_FIRST)
>> +
>> +/* clock settings (SCP and CI) for various SPI modes */
>> +#define SPI_CLK_MODE0 SPI_PPC4XX_MODE_SCP
>> +#define SPI_CLK_MODE1 0
>> +#define SPI_CLK_MODE2 SPI_PPC4XX_MODE_CI
>> +#define SPI_CLK_MODE3 (SPI_PPC4XX_MODE_SCP | SPI_PPC4XX_MODE_CI)
>
> Color me puzzled then. Either the definitions of MODE0 and MODE1
> are swapped here ... or the comments above are wrong, and SCP should
> describe "falling" vs "rising" instead of "leading" vs "trailing".
>
>
The modes were wrong. MODE0 and MODE1 were correct, but MODE2 and MODE3
were interchanged. Fixed in v7, and verified on a logic analyzer.
>> +static int spi_ppc4xx_setupxfer(struct spi_device *spi, struct spi_transfer *t)
>> +{
>> + struct ppc4xx_spi *hw = spi_master_get_devdata(spi->master);
>> + struct spi_ppc4xx_cs *cs = spi->controller_state;
>> + int scr;
>> + u8 cdm = 0;
>> + u32 speed;
>> + u8 bits_per_word;
>> +
>> + bits_per_word = (t) ? t->bits_per_word : spi->bits_per_word;
>> + speed = (t) ? t->speed_hz : spi->max_speed_hz;
>> +
>> + ...
>> +
>> + if (!speed || (speed > spi->max_speed_hz)) {
>
> This is wrong. Typical case is that t->speed_hz is zero,
> meaning "use spi->max_speed_hz" ... you treat that as an error.
>
Correct. I've fixed the logic for t->speed_hz and for t->bits_per_word.
>> + dev_err(&spi->dev, "invalid speed_hz (%d)\n", speed);
>> + return -EINVAL;
>> + }
>> +
>> + ...
>> +}
>> +
>> +static int spi_ppc4xx_setup(struct spi_device *spi)
>> +{
>> + int ret;
>> + struct spi_ppc4xx_cs *cs = spi->controller_state;
>> + int init = 0;
>
> This "init" thing is still wrong.
Correct. I've removed it entirely.
>
> Consider: board gets set up with one device. Later,
> *WHILE BUSY TRANSFERRING DATA TO/FROM THAT DEVICE*
> some other device gets instantiated. Then ...
>
>
>> + if (cs == NULL) {
>> + cs = kzalloc(sizeof *cs, GFP_KERNEL);
>> + if (!cs)
>> + return -ENOMEM;
>> + spi->controller_state = cs;
>> +
>> + /*
>> + * First time called, so let's init the SPI controller
>> + * at the end of this function
>> + */
>> + init = 1;
>
> "init" becomes true here, although the controller has
> already been initialized. If it needs to be set up,
> do it in probe() before registering the spi_master.
>
>
>> + }
>> +
>> + ...
>> +
>> + /*
>> + * New configuration (mode, speed etc) will be written to the
>> + * controller in spi_ppc4xx_setupxfer(). Only call
>> + * spi_ppc4xx_setupxfer() directly upon first initialization.
>> + */
>> + if (init) {
>> + ret = spi_ppc4xx_setupxfer(spi, NULL);
>
> ... so blam, you clobber the settings currently being used for
> the active transfer. So this would be a bug.
>
> If not ... this driver deserves a comment on exactly how
> unusual this driver is. Specifically, that all spi_device
> children must be set up *in advance* so that standard calls
> like spi_new_device() don't work with it; and why.
>
> I don't think I see anything in this driver which would
> prevent that from working, though. Sure you've got to
> have a list of chipselect GPIOs in advance, but that's
> distinct from being unable to use spi_new_device().
>
>
>> + ...
>> +}
>> +
>> +static void spi_ppc4xx_chipsel(struct spi_device *spi, int value)
>> +{
>> + struct ppc4xx_spi *hw = spi_master_get_devdata(spi->master);
>> + unsigned int cspol = spi->mode & SPI_CS_HIGH ? 1 : 0;
>> + unsigned int cs = spi->chip_select;
>> +
>> + if (!hw->num_gpios)
>> + return;
>
> Hmm, num_gpios ... can never be zero, right? You always
> set it up so that of_gpio_count() GPIOs can all be used
> as chipselects. Looks like this check is not needed.
>
I believe that it can be zero, in the case where there is a single
"always on" device. But I have modified this test to use
hw->master->num_chipselect as per your next comment. I've also added a
check for the special case of EEXIST, which on powerpc means "a hole in
the list of gpio's". I actually use this for an AVR device, because it
won't tolerate transitions on its CS lead, so I manage its CS outside of
the driver. I can explain further if you want the details of our
hardware ugliness. :-)
>> +
>> + if (cs >= hw->num_gpios)
>> + return;
>
> I guess I don't see why you have num_gpio instead of just
> using the chipselect count, either. (Assuming that the
> of_gpio_count routine isn't counting *all* gpios, instead
> of just ones allocated to this controller, which would be
> a different issue.)
>
>
Correct, and fixed in v7.
>> +
>> + if (value != BITBANG_CS_INACTIVE && value != BITBANG_CS_ACTIVE)
>> + return;
>
> Strange, what other values could be passed??
>
>
I've removed this test - it is superfluous.
>> +
>> + if (value == BITBANG_CS_INACTIVE)
>> + cspol = !cspol;
>> +
>> + gpio_set_value(hw->gpios[cs], cspol);
>> +}
>> +
>> +static irqreturn_t spi_ppc4xx_int(int irq, void *dev_id)
>> +{
>> + struct ppc4xx_spi *hw;
>> + u8 status;
>> + u8 data;
>> + unsigned int count;
>> +
>> + hw = (struct ppc4xx_spi *)dev_id;
>> +
>> + status = in_8(&hw->regs->sr);
>> + if (!status)
>> + return IRQ_NONE;
>> +
>> + /* should never happen but check anyway */
>> + if (status & SPI_PPC4XX_SR_BSY) {
>
> Maybe "if (unlikely(...)) {" then.
>
>
I added unlikely() and a comment explaining why this test might be
needed. I've not observed it myself, but the documentation seems to
allow for the possibility.
>> + u8 lstatus;
>> + int cnt = 0;
>> +
>> + dev_dbg(hw->dev, "got interrupt but spi still busy?\n");
>
> But ... *does* this ever happen? If not, I'd strike this
> code. And if it does, I'd add a comment explaining what's
> known about this hardware bug. Without this, the IRQ handler
> would look pretty tight.
>
See the comment in the v7 code for why this might be necessary.
>> + do {
>> + ndelay(10);
>> + lstatus = in_8(&hw->regs->sr);
>> + } while (++cnt < 100 && lstatus & SPI_PPC4XX_SR_BSY);
>> +
>> + if (cnt >= 100) {
>> + dev_err(hw->dev, "busywait: too many loops!\n");
>> + complete(&hw->done);
>> + return IRQ_HANDLED;
>> + } else {
>> + /* status is always 1 (RBR) here */
>> + status = in_8(&hw->regs->sr);
>> + dev_dbg(hw->dev, "loops %d status %x\n", cnt, status);
>> + }
>> + }
>> +
>> + count = hw->count;
>> + hw->count++;
>> +
>> + if (status & SPI_PPC4XX_SR_RBR) {
>> + /* Data Ready */
>
> Most SPI hardware I've seen has at most a weak distinction
> between "tx done" and "rx done" IRQs ... there's little
> point to separate IRQs, since shifting out the last TX bit
> is what shifts in the last RX bit.
>
> Unless this is unusual hardware you can probably just assume
> that there's RX data, and only read it if hw->rx is non-null.
> Or, if this is *not* set, report the odd behavior...
>
>
I've removed this test. The docs clearly state that the RBR bit is the
cause of the interrupt, so there is no reason to test it.
>> + data = in_8(&hw->regs->rxd);
>> + if (hw->rx)
>> + hw->rx[count] = data;
>> + }
>> +
>> + count++;
>> +
>> + if (count < hw->len) {
>> + data = hw->tx ? hw->tx[count] : 0;
>> + out_8(&hw->regs->txd, data);
>> + out_8(&hw->regs->cr, SPI_PPC4XX_CR_STR);
>> + } else {
>> + complete(&hw->done);
>> + }
>> +
>> + return IRQ_HANDLED;
>> +}
>> +
>> + ...
>> +
>
>> +static int __init spi_ppc4xx_of_probe(struct of_device *op,
>> + const struct of_device_id *match)
>> +{
>> + struct ppc4xx_spi *hw;
>> + struct spi_master *master;
>> + struct spi_bitbang *bbp;
>> + struct resource resource;
>> + struct device_node *np = op->node;
>> + struct device *dev = &op->dev;
>> + struct device_node *opbnp;
>> + int ret;
>> + const unsigned int *clk;
>> +
>> + master = spi_alloc_master(dev, sizeof *hw);
>> + if (master == NULL)
>> + return -ENOMEM;
>> + dev_set_drvdata(dev, master);
>> + hw = spi_master_get_devdata(master);
>> + memset(hw, 0, sizeof(struct ppc4xx_spi));
>
> That memset is not required, it comes to you pre-zeroed.
>
Removed.
>> +
>> + hw->master = spi_master_get(master);
>> + hw->dev = dev;
>> +
>> + init_completion(&hw->done);
>> +
>> + hw->num_gpios = of_gpio_count(np);
>
> Worth a comment what's going on there. I'm assuming this
> of_gpio_count() thing returns a count of GPIOs somehow
> associated with this specific device tree node, rather than
> say all GPIOs known to the device tree...
>
I've beefed up the comments for this in v7. Please let me know if you
want more.
>> + if (hw->num_gpios) {
>> + int i;
>> +
>> + hw->gpios = kzalloc(sizeof(int) * hw->num_gpios,
>> + GFP_KERNEL);
>> + if (!hw->gpios) {
>> + ret = -ENOMEM;
>> + goto free_master;
>> + }
>> +
>> + for (i = 0; i < hw->num_gpios; i++) {
>> + int gpio = of_get_gpio(np, i);
>> + if (gpio < 0) {
>> + dev_err(dev, "Invalid gpio spec %d\n", i);
>> + ret = gpio;
>> + goto free_gpios;
>> + }
>> +
>> + ret = gpio_request(gpio, np->name);
>> + if (ret < 0) {
>> + dev_err(dev, "gpio %d already in use\n", i);
>> + ret = gpio;
>> + goto free_gpios;
>> + }
>> +
>> + gpio_direction_output(gpio, 0);
>> + hw->gpios[i] = gpio;
>> + }
>> + }
>
> Else ... error, if there are no chipselects?
>
> I've got a patch pending to add a "no chipselect" spi->mode flag.
> If you expect to support that, please let me know.
>
>
I guess we should allow the case of a single device with no CS. I don't
have such a configuration, but I think the way I've written the
spi_ppc4xx_chipsel() will handle that case.
>> +
>> + /* Setup the state for the bitbang driver */
>> + bbp = &hw->bitbang;
>> + bbp->master = hw->master;
>> + bbp->setup_transfer = spi_ppc4xx_setupxfer;
>> + bbp->chipselect = spi_ppc4xx_chipsel;
>> + bbp->txrx_bufs = spi_ppc4xx_txrx;
>> + bbp->use_dma = 0;
>> + bbp->master->setup = spi_ppc4xx_setup;
>> + bbp->master->cleanup = spi_ppc4xx_cleanup;
>> + /* only one SPI controller */
>> + bbp->master->bus_num = 0;
>
> Bad assumption. There could be GPIO-based adapters,
> of course. And aren't these the cores which can be
> found on higher end Xilinx FPGAs? And, accordingly,
> integrated with any number of additional controllers?
>
> If so, the restriction is just that this controller
> be bus #0. If not ... the Kconfig should say more
> about *which* PPC4xx chips have this controller.
> (I suspect it's the latter.)
>
>
I've changed this to ...bus_num = -1. The dynamic allocation works for
me.
>> + if (bbp->master->num_chipselect == 0) {
>
> You didn't set it, so of course it's still zeroed.
>
>
Removed this test.
>> + /* this many pins in al GPIO controllers */
>> + bbp->master->num_chipselect = hw->num_gpios;
>
> So num_chipselect is alays num_gpios, and there's no point
> to having num_gpios since you could always use num_chipselect.
>
>
Correct. Substituted num_chipselect for num_gpios in v7.
>> + }
>> +
>> + ...
>> +}
>
>
^ permalink raw reply
* Subject: [PATCH v7] spi: Add PPC4xx SPI driver
From: Steven A. Falco @ 2009-06-25 19:12 UTC (permalink / raw)
To: David Brownell, Stefan Roese, linuxppc-dev@ozlabs.org
This adds a SPI driver for the SPI controller found in the IBM/AMCC
4xx PowerPC's.
Signed-off-by: Stefan Roese <sr@denx.de>
Signed-off-by: Wolfgang Ocker <weo@reccoware.de>
Acked-by: Josh Boyer <jwboyer@linux.vnet.ibm.com>
Signed-off-by: Steven A. Falco <sfalco@harris.com>
---
Note, I have not removed any of the prior sign-offs, but feel free to
look this version over very closely, and let me know if you demand a
"retraction". :-)
I've successfully used this driver on a custom PPC440EPx based board
with three devices on the spi bus, one of which uses the "chip-select
hole" feature.
Changes in v7:
- Additional comments as per David Brownell's review
- Corrected phase in mode 2 and 3
- Corrected speed and bits_per_word logic in spi_ppc4xx_setupxfer
- Removed extraneous tests as per David's review
- Added support for "holes" in the chip-select list
- Using dynamic bus allocation
- Corrected initialization logic
Changes in v6:
- Moved comment about high interrupt load to top of file and extended it
by explaining that the 4xx SPI controller has no FIFOs.
- Added parameter checking to setup() routine.
- Removed comment about LSB
- Used of_gpio_count() instead creating own static implementation as
suggested by Anton.
Changes in v5:
- Don't call setupxfer() from setup() so that the baudrate etc
won't get changed while another transfer is active, as suggested
by David Brownell.
- module_{init,exit} moved directly to the functions to which they
apply.
- Use __func__ instead of __FUNCTION__.
Changes in v4:
- Added fixes suggested by Josh Boyer
- Changed compatible property from "ibm,spi" to "ibm,ppc4xx-spi"
Changes in v3:
- When the device is removed the GPIOs are released. The memory
for the GPIO array is freed.
Changes in v2:
- Now the gpios property is correctly decoded and the
resulting gpio numbers are used as the devices chip
selects.
diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
index 83a185d..2f0a3df 100644
--- a/drivers/spi/Kconfig
+++ b/drivers/spi/Kconfig
@@ -171,6 +171,13 @@ config SPI_ORION
help
This enables using the SPI master controller on the Orion chips.
+config SPI_PPC4xx
+ tristate "PPC4xx SPI Controller"
+ depends on 4xx && SPI_MASTER
+ select SPI_BITBANG
+ help
+ This selects a driver for the PPC4xx SPI Controller.
+
config SPI_PXA2XX
tristate "PXA2xx SSP SPI master"
depends on ARCH_PXA && EXPERIMENTAL
diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile
index 5d04519..ed1d74f 100644
--- a/drivers/spi/Makefile
+++ b/drivers/spi/Makefile
@@ -23,8 +23,9 @@ obj-$(CONFIG_SPI_PXA2XX) += pxa2xx_spi.o
obj-$(CONFIG_SPI_OMAP_UWIRE) += omap_uwire.o
obj-$(CONFIG_SPI_OMAP24XX) += omap2_mcspi.o
obj-$(CONFIG_SPI_ORION) += orion_spi.o
obj-$(CONFIG_SPI_MPC52xx_PSC) += mpc52xx_psc_spi.o
obj-$(CONFIG_SPI_MPC83xx) += spi_mpc83xx.o
+obj-$(CONFIG_SPI_PPC4xx) += spi_ppc4xx.o
obj-$(CONFIG_SPI_S3C24XX_GPIO) += spi_s3c24xx_gpio.o
obj-$(CONFIG_SPI_S3C24XX) += spi_s3c24xx.o
obj-$(CONFIG_SPI_TXX9) += spi_txx9.o
diff --git a/drivers/spi/spi_ppc4xx.c b/drivers/spi/spi_ppc4xx.c
new file mode 100644
index 0000000..631bca2
--- /dev/null
+++ b/drivers/spi/spi_ppc4xx.c
@@ -0,0 +1,623 @@
+/*
+ * SPI_PPC4XX SPI controller driver.
+ *
+ * Copyright (C) 2007 Gary Jennejohn <garyj@denx.de>
+ * Copyright 2008 Stefan Roese <sr@denx.de>, DENX Software Engineering
+ * Copyright 2009 Harris Corporation, Steven A. Falco <sfalco@harris.com>
+ *
+ * Based in part on drivers/spi/spi_s3c24xx.c
+ *
+ * Copyright (c) 2006 Ben Dooks
+ * Copyright (c) 2006 Simtec Electronics
+ * Ben Dooks <ben@simtec.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ */
+
+/*
+ * The PPC4xx SPI controller has no FIFO so each sent/received byte will
+ * generate an interrupt to the CPU. This can cause high CPU utilization.
+ * This driver allows platforms to reduce the interrupt load on the CPU
+ * during SPI transfers by setting max_speed_hz via the device tree.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/wait.h>
+#include <linux/of_platform.h>
+#include <linux/of_spi.h>
+#include <linux/of_gpio.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+
+#include <linux/gpio.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/spi_bitbang.h>
+
+#include <asm/io.h>
+#include <asm/dcr.h>
+#include <asm/dcr-regs.h>
+
+/* bits in mode register - bit 0 is MSb */
+
+/*
+ * SPI_PPC4XX_MODE_SCP = 0 means "data latched on trailing edge of clock"
+ * SPI_PPC4XX_MODE_SCP = 1 means "data latched on leading edge of clock"
+ * Note: This is the inverse of CPHA.
+ */
+#define SPI_PPC4XX_MODE_SCP (0x80 >> 3)
+
+/* SPI_PPC4XX_MODE_SPE = 1 means "port enabled" */
+#define SPI_PPC4XX_MODE_SPE (0x80 >> 4)
+
+/*
+ * SPI_PPC4XX_MODE_RD = 0 means "MSB first" - this is the normal mode
+ * SPI_PPC4XX_MODE_RD = 1 means "LSB first" - this is bit-reversed mode
+ * Note: This is identical to SPI_LSB_FIRST.
+ */
+#define SPI_PPC4XX_MODE_RD (0x80 >> 5)
+
+/*
+ * SPI_PPC4XX_MODE_CI = 0 means "clock idles low"
+ * SPI_PPC4XX_MODE_CI = 1 means "clock idles high"
+ * Note: This is identical to CPOL.
+ */
+#define SPI_PPC4XX_MODE_CI (0x80 >> 6)
+
+/*
+ * SPI_PPC4XX_MODE_IL = 0 means "loopback disable"
+ * SPI_PPC4XX_MODE_IL = 1 means "loopback enable"
+ */
+#define SPI_PPC4XX_MODE_IL (0x80 >> 7)
+
+/* bits in control register */
+/* starts a transfer when set */
+#define SPI_PPC4XX_CR_STR (0x80 >> 7)
+
+/* bits in status register */
+/* port is busy with a transfer */
+#define SPI_PPC4XX_SR_BSY (0x80 >> 6)
+/* RxD ready */
+#define SPI_PPC4XX_SR_RBR (0x80 >> 7)
+
+/* the spi->mode bits understood by this driver: */
+#define MODEBITS (SPI_CPHA | SPI_CPOL | SPI_CS_HIGH | SPI_LSB_FIRST)
+
+/* clock settings (SCP and CI) for various SPI modes */
+#define SPI_CLK_MODE0 (SPI_PPC4XX_MODE_SCP | 0)
+#define SPI_CLK_MODE1 (0 | 0)
+#define SPI_CLK_MODE2 (SPI_PPC4XX_MODE_SCP | SPI_PPC4XX_MODE_CI)
+#define SPI_CLK_MODE3 (0 | SPI_PPC4XX_MODE_CI)
+
+#define DRIVER_NAME "spi_ppc4xx_of"
+
+struct spi_ppc4xx_regs {
+ u8 mode;
+ u8 rxd;
+ u8 txd;
+ u8 cr;
+ u8 sr;
+ u8 dummy;
+ /*
+ * Clock divisor modulus register
+ * This uses the follwing formula:
+ * SCPClkOut = OPBCLK/(4(CDM + 1))
+ * or
+ * CDM = (OPBCLK/4*SCPClkOut) - 1
+ * bit 0 is the MSb!
+ */
+ u8 cdm;
+};
+
+/* SPI Controller driver's private data. */
+struct ppc4xx_spi {
+ /* bitbang has to be first */
+ struct spi_bitbang bitbang;
+ struct completion done;
+
+ u64 mapbase;
+ u64 mapsize;
+ int irqnum;
+ /* need this to set the SPI clock */
+ unsigned int opb_freq;
+
+ /* for transfers */
+ int len;
+ int count;
+ /* data buffers */
+ const unsigned char *tx;
+ unsigned char *rx;
+
+ int *gpios;
+
+ struct spi_ppc4xx_regs __iomem *regs; /* pointer to the registers */
+ struct spi_master *master;
+ struct device *dev;
+};
+
+/* need this so we can set the clock in the chipselect routine */
+struct spi_ppc4xx_cs {
+ u8 mode;
+};
+
+static int spi_ppc4xx_txrx(struct spi_device *spi, struct spi_transfer *t)
+{
+ struct ppc4xx_spi *hw;
+ u8 data;
+
+ dev_dbg(&spi->dev, "txrx: tx %p, rx %p, len %d\n",
+ t->tx_buf, t->rx_buf, t->len);
+
+ hw = spi_master_get_devdata(spi->master);
+
+ hw->tx = t->tx_buf;
+ hw->rx = t->rx_buf;
+ hw->len = t->len;
+ hw->count = 0;
+
+ /* send the first byte */
+ data = hw->tx ? hw->tx[0] : 0;
+ out_8(&hw->regs->txd, data);
+ out_8(&hw->regs->cr, SPI_PPC4XX_CR_STR);
+ wait_for_completion(&hw->done);
+
+ return hw->count;
+}
+
+static int spi_ppc4xx_setupxfer(struct spi_device *spi, struct spi_transfer *t)
+{
+ struct ppc4xx_spi *hw = spi_master_get_devdata(spi->master);
+ struct spi_ppc4xx_cs *cs = spi->controller_state;
+ int scr;
+ u8 cdm = 0;
+ u32 speed;
+ u8 bits_per_word;
+
+ /* Start with the generic configuration for this device. */
+ bits_per_word = spi->bits_per_word;
+ speed = spi->max_speed_hz;
+
+ /*
+ * Modify the configuration if the transfer overrides it. Do not allow
+ * the transfer to overwrite the generic configuration with zeros.
+ */
+ if (t) {
+ if (t->bits_per_word)
+ bits_per_word = t->bits_per_word;
+
+ if (t->speed_hz)
+ speed = min(t->speed_hz, spi->max_speed_hz);
+ }
+
+ if (bits_per_word != 8) {
+ dev_err(&spi->dev, "invalid bits-per-word (%d)\n", bits_per_word);
+ return -EINVAL;
+ }
+
+ if (!speed || (speed > spi->max_speed_hz)) {
+ dev_err(&spi->dev, "invalid speed_hz (%d)\n", speed);
+ return -EINVAL;
+ }
+
+ /* Write new configration */
+ out_8(&hw->regs->mode, cs->mode);
+
+ /* Set the clock */
+ /* opb_freq was already divided by 4 */
+ scr = (hw->opb_freq / speed) - 1;
+ if (scr > 0)
+ cdm = min(scr, 0xff);
+
+ dev_dbg(&spi->dev, "setting pre-scaler to %d (hz %d)\n", cdm, speed);
+
+ if (in_8(&hw->regs->cdm) != cdm)
+ out_8(&hw->regs->cdm, cdm);
+
+ spin_lock(&hw->bitbang.lock);
+ if (!hw->bitbang.busy) {
+ hw->bitbang.chipselect(spi, BITBANG_CS_INACTIVE);
+ /* Need to ndelay here? */
+ }
+ spin_unlock(&hw->bitbang.lock);
+
+ return 0;
+}
+
+static int spi_ppc4xx_setup(struct spi_device *spi)
+{
+ struct spi_ppc4xx_cs *cs = spi->controller_state;
+
+ if (!spi->bits_per_word)
+ spi->bits_per_word = 8;
+
+ if (spi->bits_per_word != 8) {
+ dev_err(&spi->dev, "invalid bits-per-word (%d)\n",
+ spi->bits_per_word);
+ return -EINVAL;
+ }
+
+ if (!spi->max_speed_hz) {
+ dev_err(&spi->dev, "invalid max_speed_hz (must be non-zero)\n");
+ return -EINVAL;
+ }
+
+ if (spi->mode & ~MODEBITS) {
+ dev_dbg(&spi->dev, "setup: unsupported mode bits %x\n",
+ spi->mode & ~MODEBITS);
+ return -EINVAL;
+ }
+
+ if (cs == NULL) {
+ cs = kzalloc(sizeof *cs, GFP_KERNEL);
+ if (!cs)
+ return -ENOMEM;
+ spi->controller_state = cs;
+ }
+
+ /*
+ * We set all bits of the SPI0_MODE register, so,
+ * no need to read-modify-write
+ */
+ cs->mode = SPI_PPC4XX_MODE_SPE;
+
+ switch (spi->mode & (SPI_CPHA | SPI_CPOL)) {
+ case SPI_MODE_0:
+ cs->mode |= SPI_CLK_MODE0;
+ break;
+ case SPI_MODE_1:
+ cs->mode |= SPI_CLK_MODE1;
+ break;
+ case SPI_MODE_2:
+ cs->mode |= SPI_CLK_MODE2;
+ break;
+ case SPI_MODE_3:
+ cs->mode |= SPI_CLK_MODE3;
+ break;
+ }
+
+ if (spi->mode & SPI_LSB_FIRST)
+ cs->mode |= SPI_PPC4XX_MODE_RD;
+
+ dev_dbg(&spi->dev, "%s: mode %d, %u bpw, %d hz\n",
+ __func__, spi->mode, spi->bits_per_word,
+ spi->max_speed_hz);
+
+ return 0;
+}
+
+static void spi_ppc4xx_chipsel(struct spi_device *spi, int value)
+{
+ struct ppc4xx_spi *hw = spi_master_get_devdata(spi->master);
+ unsigned int cs = spi->chip_select;
+ unsigned int cspol;
+
+ /*
+ * If there are no chip selects at all, or if this is the special case of
+ * a non-existent (dummy) chip select, do nothing.
+ */
+
+ if (!hw->master->num_chipselect || hw->gpios[cs] == -EEXIST)
+ return;
+
+ cspol = spi->mode & SPI_CS_HIGH ? 1 : 0;
+ if (value == BITBANG_CS_INACTIVE)
+ cspol = !cspol;
+
+ gpio_set_value(hw->gpios[cs], cspol);
+}
+
+static irqreturn_t spi_ppc4xx_int(int irq, void *dev_id)
+{
+ struct ppc4xx_spi *hw;
+ u8 status;
+ u8 data;
+ unsigned int count;
+
+ hw = (struct ppc4xx_spi *)dev_id;
+
+ status = in_8(&hw->regs->sr);
+ if (!status)
+ return IRQ_NONE;
+
+ /*
+ * BSY de-asserts one cycle after the transfer is complete. The interrupt
+ * is asserted after the transfer is complete. The exact relationship is
+ * not documented, hence this code.
+ */
+
+ if (unlikely(status & SPI_PPC4XX_SR_BSY)) {
+ u8 lstatus;
+ int cnt = 0;
+
+ dev_dbg(hw->dev, "got interrupt but spi still busy?\n");
+ do {
+ ndelay(10);
+ lstatus = in_8(&hw->regs->sr);
+ } while (++cnt < 100 && lstatus & SPI_PPC4XX_SR_BSY);
+
+ if (cnt >= 100) {
+ dev_err(hw->dev, "busywait: too many loops!\n");
+ complete(&hw->done);
+ return IRQ_HANDLED;
+ } else {
+ /* status is always 1 (RBR) here */
+ status = in_8(&hw->regs->sr);
+ dev_dbg(hw->dev, "loops %d status %x\n", cnt, status);
+ }
+ }
+
+ count = hw->count;
+ hw->count++;
+
+ /* RBR triggered this interrupt. Therefore, data must be ready. */
+ data = in_8(&hw->regs->rxd);
+ if (hw->rx)
+ hw->rx[count] = data;
+
+ count++;
+
+ if (count < hw->len) {
+ data = hw->tx ? hw->tx[count] : 0;
+ out_8(&hw->regs->txd, data);
+ out_8(&hw->regs->cr, SPI_PPC4XX_CR_STR);
+ } else {
+ complete(&hw->done);
+ }
+
+ return IRQ_HANDLED;
+}
+
+static void spi_ppc4xx_cleanup(struct spi_device *spi)
+{
+ kfree(spi->controller_state);
+}
+
+static void spi_ppc4xx_enable(struct ppc4xx_spi *hw)
+{
+ /*
+ * On all 4xx PPC's the SPI bus is shared/multiplexed with
+ * the 2nd I2C bus. We need to enable the the SPI bus before
+ * using it.
+ */
+
+ /* need to clear bit 14 to enable SPC */
+ dcri_clrset(SDR0, SDR0_PFC1, 0x80000000 >> 14, 0);
+}
+
+static void free_gpios(struct ppc4xx_spi *hw)
+{
+ if (hw->master->num_chipselect) {
+ int i;
+ for (i = 0; i < hw->master->num_chipselect; i++)
+ if (gpio_is_valid(hw->gpios[i]))
+ gpio_free(hw->gpios[i]);
+
+ kfree(hw->gpios);
+ hw->gpios = NULL;
+ }
+}
+
+/*
+ * of_device layer stuff...
+ */
+static int __init spi_ppc4xx_of_probe(struct of_device *op,
+ const struct of_device_id *match)
+{
+ struct ppc4xx_spi *hw;
+ struct spi_master *master;
+ struct spi_bitbang *bbp;
+ struct resource resource;
+ struct device_node *np = op->node;
+ struct device *dev = &op->dev;
+ struct device_node *opbnp;
+ int ret;
+ int num_gpios;
+ const unsigned int *clk;
+
+ master = spi_alloc_master(dev, sizeof *hw);
+ if (master == NULL)
+ return -ENOMEM;
+ dev_set_drvdata(dev, master);
+ hw = spi_master_get_devdata(master);
+ hw->master = spi_master_get(master);
+ hw->dev = dev;
+
+ init_completion(&hw->done);
+
+ /*
+ * A count of zero implies a single SPI device without any chip-select.
+ * Note that of_gpio_count counts all gpios assigned to this spi master.
+ * This includes both "null" gpio's and real ones.
+ */
+ num_gpios = of_gpio_count(np);
+ if (num_gpios) {
+ int i;
+
+ hw->gpios = kzalloc(sizeof(int) * num_gpios, GFP_KERNEL);
+ if (!hw->gpios) {
+ ret = -ENOMEM;
+ goto free_master;
+ }
+
+ for (i = 0; i < num_gpios; i++) {
+ int gpio;
+ enum of_gpio_flags flags;
+
+ gpio = of_get_gpio_flags(np, i, &flags);
+ hw->gpios[i] = gpio;
+
+ if (gpio_is_valid(gpio)) {
+ /* Real CS - set the initial state. */
+ ret = gpio_request(gpio, np->name);
+ if (ret < 0) {
+ dev_err(dev, "can't request gpio #%d: %d\n",
+ i, ret);
+ goto free_gpios;
+ }
+
+ gpio_direction_output(gpio,
+ !!(flags & OF_GPIO_ACTIVE_LOW));
+ } else if (gpio == -EEXIST) {
+ ; /* No CS, but that's OK. */
+ } else {
+ dev_err(dev, "invalid gpio #%d: %d\n", i, gpio);
+ ret = -EINVAL;
+ goto free_gpios;
+ }
+ }
+ }
+
+ /* Setup the state for the bitbang driver */
+ bbp = &hw->bitbang;
+ bbp->master = hw->master;
+ bbp->setup_transfer = spi_ppc4xx_setupxfer;
+ bbp->chipselect = spi_ppc4xx_chipsel;
+ bbp->txrx_bufs = spi_ppc4xx_txrx;
+ bbp->use_dma = 0;
+ bbp->master->setup = spi_ppc4xx_setup;
+ bbp->master->cleanup = spi_ppc4xx_cleanup;
+
+ /* Allocate bus num dynamically. */
+ bbp->master->bus_num = -1;
+
+ /* this many pins in all GPIO controllers */
+ bbp->master->num_chipselect = num_gpios;
+
+ /* Get the clock for the OPB */
+ opbnp = of_find_compatible_node(NULL, NULL, "ibm,opb");
+ if (opbnp == NULL) {
+ dev_err(dev, "OPB: cannot find node\n");
+ ret = -ENODEV;
+ goto free_gpios;
+ }
+ /* Get the clock (Hz) for the OPB */
+ clk = of_get_property(opbnp, "clock-frequency", NULL);
+ if (clk == NULL) {
+ dev_err(dev, "OPB: no clock-frequency property set\n");
+ of_node_put(opbnp);
+ ret = -ENODEV;
+ goto free_gpios;
+ }
+ hw->opb_freq = *clk;
+ hw->opb_freq >>= 2;
+ of_node_put(opbnp);
+
+ ret = of_address_to_resource(np, 0, &resource);
+ if (ret) {
+ dev_err(dev, "error while parsing device node resource\n");
+ goto free_gpios;
+ }
+ hw->mapbase = resource.start;
+ hw->mapsize = resource.end - resource.start + 1;
+
+ /* Sanity check */
+ if (hw->mapsize < sizeof(struct spi_ppc4xx_regs)) {
+ dev_err(dev, "too small to map registers\n");
+ ret = -EINVAL;
+ goto free_gpios;
+ }
+
+ /* Request IRQ */
+ hw->irqnum = irq_of_parse_and_map(np, 0);
+ ret = request_irq(hw->irqnum, spi_ppc4xx_int,
+ IRQF_DISABLED, "spi_ppc4xx_of", (void *)hw);
+ if (ret) {
+ dev_err(dev, "unable to allocate interrupt\n");
+ goto free_gpios;
+ }
+
+ if (!request_mem_region(hw->mapbase, hw->mapsize, DRIVER_NAME)) {
+ dev_err(dev, "resource unavailable\n");
+ ret = -EBUSY;
+ goto request_mem_error;
+ }
+
+ hw->regs = ioremap(hw->mapbase, sizeof(struct spi_ppc4xx_regs));
+
+ if (!hw->regs) {
+ dev_err(dev, "unable to memory map registers\n");
+ ret = -ENXIO;
+ goto map_io_error;
+ }
+
+ spi_ppc4xx_enable(hw);
+
+ /* Finally register our spi controller */
+ dev->dma_mask = 0;
+ ret = spi_bitbang_start(bbp);
+ if (ret) {
+ dev_err(dev, "failed to register SPI master\n");
+ goto unmap_regs;
+ }
+
+ dev_info(dev, "driver initialized\n");
+ of_register_spi_devices(master, np);
+
+ return 0;
+
+unmap_regs:
+ iounmap(hw->regs);
+map_io_error:
+ release_mem_region(hw->mapbase, hw->mapsize);
+request_mem_error:
+ free_irq(hw->irqnum, hw);
+free_gpios:
+ free_gpios(hw);
+free_master:
+ dev_set_drvdata(dev, NULL);
+ spi_master_put(master);
+
+ dev_err(dev, "initialization failed\n");
+ return ret;
+}
+
+static int __exit spi_ppc4xx_of_remove(struct of_device *op)
+{
+ struct spi_master *master = dev_get_drvdata(&op->dev);
+ struct ppc4xx_spi *hw = spi_master_get_devdata(master);
+
+ spi_bitbang_stop(&hw->bitbang);
+ dev_set_drvdata(&op->dev, NULL);
+ release_mem_region(hw->mapbase, hw->mapsize);
+ free_irq(hw->irqnum, hw);
+ iounmap(hw->regs);
+ free_gpios(hw);
+ return 0;
+}
+
+static struct of_device_id spi_ppc4xx_of_match[] = {
+ { .compatible = "ibm,ppc4xx-spi", },
+ {},
+};
+
+MODULE_DEVICE_TABLE(of, spi_ppc4xx_of_match);
+
+static struct of_platform_driver spi_ppc4xx_of_driver = {
+ .match_table = spi_ppc4xx_of_match,
+ .probe = spi_ppc4xx_of_probe,
+ .remove = __exit_p(spi_ppc4xx_of_remove),
+ .driver = {
+ .name = DRIVER_NAME,
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init spi_ppc4xx_init(void)
+{
+ return of_register_platform_driver(&spi_ppc4xx_of_driver);
+}
+module_init(spi_ppc4xx_init);
+
+static void __exit spi_ppc4xx_exit(void)
+{
+ of_unregister_platform_driver(&spi_ppc4xx_of_driver);
+}
+module_exit(spi_ppc4xx_exit);
+
+MODULE_AUTHOR("Gary Jennejohn & Stefan Roese");
+MODULE_DESCRIPTION("Simple PPC4xx SPI Driver");
+MODULE_LICENSE("GPL");
^ permalink raw reply related
* Re: 85xx Address space query
From: Scott Wood @ 2009-06-25 19:34 UTC (permalink / raw)
To: kernel mailz; +Cc: linuxppc-dev
In-Reply-To: <abe8a1fd0906250351y1aadc153m9f52f65a5860a2ca@mail.gmail.com>
kernel mailz wrote:
> So this means
> when kernel gets interrupted by app which may be in PID=5 (say)
> kernel translations for PID=0 remain valid ?
> I am not able to follow Scott
Yes, exactly. They're valid even in userspace, except to the extent that the
kernel marks them supervisor-only.
-Scott
^ permalink raw reply
* Re: Direct MII connection between MPC8313 and VIRTEX FPGA
From: Grant Likely @ 2009-06-25 20:05 UTC (permalink / raw)
To: Frank Prepelica; +Cc: linuxppc-dev
In-Reply-To: <29DC34A6B43468409F5A371CFE34E849D7ED46@ex01.ads.ubidyne.de>
On Thu, Jun 25, 2009 at 9:11 AM, Frank
Prepelica<Frank.Prepelica@ubidyne.com> wrote:
> Hi all,
>
> we removed the ethernet PHYs (MARVELL) from our customized board (based on MPC8313ERDB) and
> connected the CPU Ethernet lines directly to a FPGA which is now emulating the PHY. But the ifconfig
> command cannot find that eth device anymore. Does the emulated PHY needs to provide MDIO
> information that the ETH device can be found again?
No, you just need to make sure that the Ethernet driver is able to
support fixed speed MII links without a PHY. It's trivial to do, but
not all drivers support it. Search for "current-speed" in
drivers/net/fec_mpc52xx.c for an example.
g.
--
Grant Likely, B.Sc., P.Eng.
Secret Lab Technologies Ltd.
^ permalink raw reply
* Re: Subject: [PATCH v7] spi: Add PPC4xx SPI driver
From: David Brownell @ 2009-06-26 4:04 UTC (permalink / raw)
To: Steven A. Falco; +Cc: linuxppc-dev@ozlabs.org, Stefan Roese
In-Reply-To: <4A43CC2C.1030409@harris.com>
On Thursday 25 June 2009, Steven A. Falco wrote:
> + if (spi->mode & ~MODEBITS) {
> + dev_dbg(&spi->dev, "setup: unsupported mode bits %x\n",
> + spi->mode & ~MODEBITS);
> + return -EINVAL;
> + }
This wasn't tested against 2.6.30-rc1 was it?
See the recent fixup patch I sent. There's a spi_master->modebits
mask that should have been initialized, and which eliminates the
need for tests like that ...
> + dev_dbg(&spi->dev, "%s: mode %d, %u bpw, %d hz\n",
> + __func__, spi->mode, spi->bits_per_word,
> + spi->max_speed_hz);
> +
... also the SPI core now provides a *standard* format debug
message for that stuff. It also handles one more thing, which
I expect to see fixed in a v8 of this patch ... :)
- Dave
^ permalink raw reply
* [git pull] Please pull powerpc.git merge branch
From: Benjamin Herrenschmidt @ 2009-06-26 7:19 UTC (permalink / raw)
To: Linus Torvalds; +Cc: linuxppc-dev list, Andrew Morton, Linux Kernel list
Hi Linus !
I would have hoped to get that stuff in before -rc1 but heh, I got sick
for a couple of days, a distracted by some other stuff for a couple more
and here we are, I missed it :-)
Anyway, here are a bunch of relatively small ppc bits, almost all are
bug fixes, mostly regressions, with the notable exception of one patch
which I decided was worth taking a chance, which is the addition of
lockdep/irqtrace support for ppc32 which has been around for 2 or 3
weeks and seems to be working well (it already found a couple of
bugs !).
The following changes since commit 987fed3bf6982f2627d4fa242caa9026ef61132a:
Linus Torvalds (1):
Merge branch 'drm-fixes' of git://git.kernel.org/.../airlied/drm-2.6
are available in the git repository at:
git://git.kernel.org/pub/scm/linux/kernel/git/benh/powerpc.git merge
Adrian Reber (1):
powerpc/rtas: Fix watchdog driver temperature read functionality
Anton Vorontsov (1):
powerpc/85xx: Make eSDHC 1-bit only transfer mode default for MPC8569E-MDS
Benjamin Herrenschmidt (13):
powerpc/mpic: Fix mapping of "DCR" based MPIC variants
powerpc/pmac: Fix issues with PowerMac "PowerSurge" SMP
powerpc/mm: Make k(un)map_atomic out of line
powerpc/pmac: Fix DMA ops for MacIO devices
powerpc: Map more memory early on 601 processors
powerpc: Add irqtrace support for 32-bit powerpc
powerpc/rtas: Turn rtas lock into a raw spinlock
powerpc: Use one common impl. of RTAS timebase sync and use raw spinlock
powerpc/pasemi: Use raw spinlock in SMP TB sync
powerpc/of: Fix usage of dev_set_name() in of_device_alloc()
powerpc/440: Fix warning early debug code
powerpc/mm: Fix potential access to freed pages when using hugetlbfs
Merge commit 'kumar/next' into merge
Gerhard Pircher (1):
powerpc/amigaone: Limit ISA I/O range to 4k in the device tree
Huang Weiyi (1):
powerpc/85xx: remove duplicated #include
Jon Smirl (1):
powerpc: Have git ignore generated files from dtc compile
Kumar Gala (6):
powerpc/cpm1: Remove IMAP_ADDR
powerpc/85xx: Stop using ppc_md.init on socrates
powerpc/85xx: Fix issue found by lockdep trace in smp_85xx_kick_cpu
powerpc: Refactor device tree binding
powerpc: Fix output from show_regs
powerpc: Fix mpic alloc warning
Michael Ellerman (1):
powerpc: Swiotlb breaks pseries
Randy Vinson (1):
powerpc/85xx: Fix FSL RapidIO probing on MDS boards
Sean MacLennan (1):
powerpc/warp: Platform fix for i2c change
Sonny Rao (2):
powerpc/BSR: add 4096 byte BSR size
powerpc/BSR: Fix BSR to allow mmap of small BSR on 64k kernel
Timur Tabi (1):
powerpc/qe: add polling timeout to qe_issue_cmd()
Documentation/powerpc/booting-without-of.txt | 1168 +---------------------
Documentation/powerpc/dts-bindings/4xx/emac.txt | 148 +++
Documentation/powerpc/dts-bindings/gpio/gpio.txt | 50 +
Documentation/powerpc/dts-bindings/gpio/mdio.txt | 19 +
Documentation/powerpc/dts-bindings/marvell.txt | 521 ++++++++++
Documentation/powerpc/dts-bindings/phy.txt | 25 +
Documentation/powerpc/dts-bindings/spi-bus.txt | 57 ++
Documentation/powerpc/dts-bindings/usb-ehci.txt | 25 +
Documentation/powerpc/dts-bindings/xilinx.txt | 295 ++++++
arch/powerpc/Kconfig | 1 -
arch/powerpc/boot/.gitignore | 10 +
arch/powerpc/boot/dts/amigaone.dts | 4 +-
arch/powerpc/boot/dts/mpc8569mds.dts | 1 +
arch/powerpc/include/asm/cpm1.h | 2 -
arch/powerpc/include/asm/dma-mapping.h | 24 +-
arch/powerpc/include/asm/highmem.h | 57 +-
arch/powerpc/include/asm/hw_irq.h | 20 +-
arch/powerpc/include/asm/pte-hash64-64k.h | 3 +-
arch/powerpc/include/asm/rtas.h | 5 +-
arch/powerpc/kernel/entry_32.S | 127 +++-
arch/powerpc/kernel/head_32.S | 17 +-
arch/powerpc/kernel/of_device.c | 2 +-
arch/powerpc/kernel/process.c | 2 +-
arch/powerpc/kernel/rtas.c | 69 ++-
arch/powerpc/kernel/setup_32.c | 2 +
arch/powerpc/kernel/smp.c | 3 +-
arch/powerpc/kernel/udbg_16550.c | 2 +-
arch/powerpc/mm/Makefile | 1 +
arch/powerpc/mm/highmem.c | 77 ++
arch/powerpc/platforms/44x/warp.c | 44 +-
arch/powerpc/platforms/85xx/mpc85xx_mds.c | 1 +
arch/powerpc/platforms/85xx/smp.c | 9 +-
arch/powerpc/platforms/85xx/socrates.c | 6 +-
arch/powerpc/platforms/85xx/xes_mpc85xx.c | 1 -
arch/powerpc/platforms/cell/smp.c | 30 +-
arch/powerpc/platforms/chrp/smp.c | 33 +-
arch/powerpc/platforms/pasemi/setup.c | 15 +-
arch/powerpc/platforms/powermac/setup.c | 41 +-
arch/powerpc/platforms/powermac/smp.c | 166 ++--
arch/powerpc/platforms/pseries/smp.c | 30 +-
arch/powerpc/sysdev/mpic.c | 34 +-
arch/powerpc/sysdev/qe_lib/qe.c | 9 +-
drivers/char/bsr.c | 42 +-
drivers/macintosh/macio_asic.c | 11 +
drivers/watchdog/wdrtas.c | 8 +-
scripts/dtc/.gitignore | 5 +
46 files changed, 1691 insertions(+), 1531 deletions(-)
create mode 100644 Documentation/powerpc/dts-bindings/4xx/emac.txt
create mode 100644 Documentation/powerpc/dts-bindings/gpio/gpio.txt
create mode 100644 Documentation/powerpc/dts-bindings/gpio/mdio.txt
create mode 100644 Documentation/powerpc/dts-bindings/marvell.txt
create mode 100644 Documentation/powerpc/dts-bindings/phy.txt
create mode 100644 Documentation/powerpc/dts-bindings/spi-bus.txt
create mode 100644 Documentation/powerpc/dts-bindings/usb-ehci.txt
create mode 100644 Documentation/powerpc/dts-bindings/xilinx.txt
create mode 100644 arch/powerpc/mm/highmem.c
create mode 100644 scripts/dtc/.gitignore
^ permalink raw reply
* Re: ALSA fixes for non-coherent ppc32 again
From: Gerhard Pircher @ 2009-06-26 13:14 UTC (permalink / raw)
To: Takashi Iwai; +Cc: linuxppc-dev
In-Reply-To: <s5hr5xa9d5q.wl%tiwai@suse.de>
-------- Original-Nachricht --------
> Datum: Wed, 24 Jun 2009 11:47:13 +0200
> Von: Takashi Iwai <tiwai@suse.de>
> An: "Gerhard Pircher" <gerhard_pircher@gmx.net>
> CC: benh@kernel.crashing.org, linuxppc-dev@ozlabs.org
> Betreff: Re: ALSA fixes for non-coherent ppc32 again
> At Wed, 24 Jun 2009 10:46:01 +0200,
> Gerhard Pircher wrote:
> >
> >
> > -------- Original-Nachricht --------
> > > Datum: Tue, 23 Jun 2009 23:42:24 +0200
> > > Von: "Gerhard Pircher" <gerhard_pircher@gmx.net>
> > > An: benh@kernel.crashing.org, tiwai@suse.de
> > > CC: linuxppc-dev@ozlabs.org
> > > Betreff: Re: ALSA fixes for non-coherent ppc32 again
> >
> > > Okay, that's wrong. I somehow messed up the .config file. It doesn't
> > > compile, too.
> > I got it to compile now and it seems to work fine. I overlooked a typo
> > in sound/core/Makefile first (ifndef CONFIG_SND_NONCOHERNT_DMA.)
>
> Gah, thanks, fixed now on the git tree too.
The Kconfig option still needs to be fixed, otherwise SND_COHERENT_DMA
isn't selected for my "PPC32 && NOT_COHERENT_CACHE" machine.
config SND_NONCOHERENT_DMA
def_bool n <-- should be "y"
depends on (PPC32 && NOT_COHERENT_CACHE)...
BTW: Can you put me on CC: please, if you bring up this topic on
linux-arch or so?
Gerhard
--
GRATIS für alle GMX-Mitglieder: Die maxdome Movie-FLAT!
Jetzt freischalten unter http://portal.gmx.net/de/go/maxdome01
^ permalink raw reply
* [PATCH] Remove 'SBC8240 Wind River' Device Driver Code
From: Subrata Modak @ 2009-06-26 14:25 UTC (permalink / raw)
To: Scott Wood, David Woodhouse
Cc: carolyn.j.smith, Stephen Rothwell, Adrian Bunk, Jim Cromie,
linux-kernel, Linuxppc-dev, Sachin P Sant, linux-next,
Subrata Modak, Alexander Beregalov, Balbir Singh
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1: Type: text/plain, Size: 10601 bytes --]
Hi David/Scott,
Today's next tree(20090626) produced the following build error:
CC [M] drivers/mtd/maps/sbc8240.o
drivers/mtd/maps/sbc8240.c:31:1: warning: "DEBUG" redefined
In file included from drivers/mtd/maps/sbc8240.c:23:
include/linux/mtd/mtd.h:333:1: warning: this is the location of the previous definition
drivers/mtd/maps/sbc8240.c: In function 'init_sbc8240_mtd':
drivers/mtd/maps/sbc8240.c:172: warning: passing argument 1 of 'simple_map_init' from incompatible pointer type
drivers/mtd/maps/sbc8240.c:177: error: 'struct mtd_info' has no member named 'module'
make[3]: *** [drivers/mtd/maps/sbc8240.o] Error 1
make[2]: *** [drivers/mtd/maps] Error 2
make[1]: *** [drivers/mtd] Error 2
make: *** [drivers] Error 2
I remember reporting this log back in April, when you suggested in removing it:
http://lkml.org/lkml/2009/4/21/476,
>On Tue, 2009-04-21 at 15:00 -0500, Scott Wood wrote:
>Subrata Modak wrote:
> > This is a very old one. Doesn´t seem to go away. Reported this earlier
> > on 14th April:
> > http://lkml.org/lkml/2009/4/14/483,
> >
> > CC [M] drivers/mtd/maps/sbc8240.o
> > drivers/mtd/maps/sbc8240.c:31:1: warning: "DEBUG" redefined
> > In file included from drivers/mtd/maps/sbc8240.c:23:
> > include/linux/mtd/mtd.h:339:1: warning: this is the location of the
> > previous definition
> > drivers/mtd/maps/sbc8240.c: In function ‘init_sbc8240_mtd’:
> > drivers/mtd/maps/sbc8240.c:172: error: ‘sbc8240_mtd’ undeclared (first
> > use in this function)
> > drivers/mtd/maps/sbc8240.c:172: error: (Each undeclared identifier is
> > reported only once
> > drivers/mtd/maps/sbc8240.c:172: error: for each function it appears in.)
> > drivers/mtd/maps/sbc8240.c: In function ‘cleanup_sbc8240_mtd’:
> > drivers/mtd/maps/sbc8240.c:233: error: ‘sbc8240_mtd’ undeclared (first
> > use in this function)
>
> This looks like an arch/ppc orphan. It's not enabled by any defconfig,
> and it doesn't look like it does anything that physmap_of can't do.
>
> I'd just remove it.
>
> -Scott
I tried to gather some more info about this driver from the link
mentioned in Kconfig:
http://www.windriver.com/products/sbc8240/,
without much success.
If there are no issues, can you please apply this patch to remove it ?
To: David Woodhouse <dwmw2@infradead.org>,
To: Scott Wood <scottwood@freescale.com>,
Cc: Jim Cromie <jim.cromie@gmail.com>,
Cc: carolyn.j.smith@exgate.tek.com,
Cc: Adrian Bunk <bunk@kernel.org>,
Cc: Sachin P Sant <sachinp@linux.vnet.ibm.com>,
Cc: Balbir Singh <balbir@linux.vnet.ibm.com>,
Cc: Stephen Rothwell <sfr@canb.auug.org.au>,
Cc: linux-kernel <linux-kernel@vger.kernel.org>,
Cc: Linuxppc-dev <Linuxppc-dev@ozlabs.org>,
Cc: linux-next <linux-next@vger.kernel.org>,
Cc: Alexander Beregalov <a.beregalov@gmail.com>
Signed-off-by: Subrata Modak <subrata@linux.vnet.ibm.com>
Tested-on-PPC64-by: Subrata Modak <subrata@linux.vnet.ibm.com>
---
diff -uprN a/drivers/mtd/maps/Kconfig b/drivers/mtd/maps/Kconfig
--- a/drivers/mtd/maps/Kconfig 2009-06-26 07:36:23.000000000 -0500
+++ b/drivers/mtd/maps/Kconfig 2009-06-26 07:39:34.000000000 -0500
@@ -284,13 +284,6 @@ config MTD_L440GX
BE VERY CAREFUL.
-config MTD_SBC8240
- tristate "Flash device on SBC8240"
- depends on MTD_JEDECPROBE && 8260
- help
- Flash access on the SBC8240 board from Wind River. See
- <http://www.windriver.com/products/sbc8240/>
-
config MTD_TQM8XXL
tristate "CFI Flash device mapped on TQM8XXL"
depends on MTD_CFI && TQM8xxL
diff -uprN a/drivers/mtd/maps/Makefile b/drivers/mtd/maps/Makefile
--- a/drivers/mtd/maps/Makefile 2009-06-26 07:36:23.000000000 -0500
+++ b/drivers/mtd/maps/Makefile 2009-06-26 07:40:03.000000000 -0500
@@ -50,7 +50,6 @@ obj-$(CONFIG_MTD_UCLINUX) += uclinux.o
obj-$(CONFIG_MTD_NETtel) += nettel.o
obj-$(CONFIG_MTD_SCB2_FLASH) += scb2_flash.o
obj-$(CONFIG_MTD_H720X) += h720x-flash.o
-obj-$(CONFIG_MTD_SBC8240) += sbc8240.o
obj-$(CONFIG_MTD_IXP4XX) += ixp4xx.o
obj-$(CONFIG_MTD_IXP2000) += ixp2000.o
obj-$(CONFIG_MTD_WRSBC8260) += wr_sbc82xx_flash.o
diff -uprN a/drivers/mtd/maps/sbc8240.c b/drivers/mtd/maps/sbc8240.c
--- a/drivers/mtd/maps/sbc8240.c 2009-06-26 07:36:23.000000000 -0500
+++ b/drivers/mtd/maps/sbc8240.c 1969-12-31 18:00:00.000000000 -0600
@@ -1,250 +0,0 @@
-/*
- * Handle mapping of the flash memory access routines on the SBC8240 board.
- *
- * Carolyn Smith, Tektronix, Inc.
- *
- * This code is GPLed
- */
-
-/*
- * The SBC8240 has 2 flash banks.
- * Bank 0 is a 512 KiB AMD AM29F040B; 8 x 64 KiB sectors.
- * It contains the U-Boot code (7 sectors) and the environment (1 sector).
- * Bank 1 is 4 x 1 MiB AMD AM29LV800BT; 15 x 64 KiB sectors, 1 x 32 KiB sector,
- * 2 x 8 KiB sectors, 1 x 16 KiB sectors.
- * Both parts are JEDEC compatible.
- */
-
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <asm/io.h>
-
-#include <linux/mtd/mtd.h>
-#include <linux/mtd/map.h>
-#include <linux/mtd/cfi.h>
-
-#ifdef CONFIG_MTD_PARTITIONS
-#include <linux/mtd/partitions.h>
-#endif
-
-#define DEBUG
-
-#ifdef DEBUG
-# define debugk(fmt,args...) printk(fmt ,##args)
-#else
-# define debugk(fmt,args...)
-#endif
-
-
-#define WINDOW_ADDR0 0xFFF00000 /* 512 KiB */
-#define WINDOW_SIZE0 0x00080000
-#define BUSWIDTH0 1
-
-#define WINDOW_ADDR1 0xFF000000 /* 4 MiB */
-#define WINDOW_SIZE1 0x00400000
-#define BUSWIDTH1 8
-
-#define MSG_PREFIX "sbc8240:" /* prefix for our printk()'s */
-#define MTDID "sbc8240-%d" /* for mtdparts= partitioning */
-
-
-static struct map_info sbc8240_map[2] = {
- {
- .name = "sbc8240 Flash Bank #0",
- .size = WINDOW_SIZE0,
- .bankwidth = BUSWIDTH0,
- },
- {
- .name = "sbc8240 Flash Bank #1",
- .size = WINDOW_SIZE1,
- .bankwidth = BUSWIDTH1,
- }
-};
-
-#define NUM_FLASH_BANKS ARRAY_SIZE(sbc8240_map)
-
-/*
- * The following defines the partition layout of SBC8240 boards.
- *
- * See include/linux/mtd/partitions.h for definition of the
- * mtd_partition structure.
- *
- * The *_max_flash_size is the maximum possible mapped flash size
- * which is not necessarily the actual flash size. It must correspond
- * to the value specified in the mapping definition defined by the
- * "struct map_desc *_io_desc" for the corresponding machine.
- */
-
-#ifdef CONFIG_MTD_PARTITIONS
-
-static struct mtd_partition sbc8240_uboot_partitions [] = {
- /* Bank 0 */
- {
- .name = "U-boot", /* U-Boot Firmware */
- .offset = 0,
- .size = 0x00070000, /* 7 x 64 KiB sectors */
- .mask_flags = MTD_WRITEABLE, /* force read-only */
- },
- {
- .name = "environment", /* U-Boot environment */
- .offset = 0x00070000,
- .size = 0x00010000, /* 1 x 64 KiB sector */
- },
-};
-
-static struct mtd_partition sbc8240_fs_partitions [] = {
- {
- .name = "jffs", /* JFFS filesystem */
- .offset = 0,
- .size = 0x003C0000, /* 4 * 15 * 64KiB */
- },
- {
- .name = "tmp32",
- .offset = 0x003C0000,
- .size = 0x00020000, /* 4 * 32KiB */
- },
- {
- .name = "tmp8a",
- .offset = 0x003E0000,
- .size = 0x00008000, /* 4 * 8KiB */
- },
- {
- .name = "tmp8b",
- .offset = 0x003E8000,
- .size = 0x00008000, /* 4 * 8KiB */
- },
- {
- .name = "tmp16",
- .offset = 0x003F0000,
- .size = 0x00010000, /* 4 * 16KiB */
- }
-};
-
-/* trivial struct to describe partition information */
-struct mtd_part_def
-{
- int nums;
- unsigned char *type;
- struct mtd_partition* mtd_part;
-};
-
-static struct mtd_info *sbc8240_mtd[NUM_FLASH_BANKS];
-static struct mtd_part_def sbc8240_part_banks[NUM_FLASH_BANKS];
-
-
-#endif /* CONFIG_MTD_PARTITIONS */
-
-
-static int __init init_sbc8240_mtd (void)
-{
- static struct _cjs {
- u_long addr;
- u_long size;
- } pt[NUM_FLASH_BANKS] = {
- {
- .addr = WINDOW_ADDR0,
- .size = WINDOW_SIZE0
- },
- {
- .addr = WINDOW_ADDR1,
- .size = WINDOW_SIZE1
- },
- };
-
- int devicesfound = 0;
- int i,j;
-
- for (i = 0; i < NUM_FLASH_BANKS; i++) {
- printk (KERN_NOTICE MSG_PREFIX
- "Probing 0x%08lx at 0x%08lx\n", pt[i].size, pt[i].addr);
-
- sbc8240_map[i].map_priv_1 =
- (unsigned long) ioremap (pt[i].addr, pt[i].size);
- if (!sbc8240_map[i].map_priv_1) {
- printk (MSG_PREFIX "failed to ioremap\n");
- for (j = 0; j < i; j++) {
- iounmap((void *) sbc8240_map[j].map_priv_1);
- sbc8240_map[j].map_priv_1 = 0;
- }
- return -EIO;
- }
- simple_map_init(&sbc8240_mtd[i]);
-
- sbc8240_mtd[i] = do_map_probe("jedec_probe", &sbc8240_map[i]);
-
- if (sbc8240_mtd[i]) {
- sbc8240_mtd[i]->module = THIS_MODULE;
- devicesfound++;
- } else {
- if (sbc8240_map[i].map_priv_1) {
- iounmap((void *) sbc8240_map[i].map_priv_1);
- sbc8240_map[i].map_priv_1 = 0;
- }
- }
- }
-
- if (!devicesfound) {
- printk(KERN_NOTICE MSG_PREFIX
- "No suppported flash chips found!\n");
- return -ENXIO;
- }
-
-#ifdef CONFIG_MTD_PARTITIONS
- sbc8240_part_banks[0].mtd_part = sbc8240_uboot_partitions;
- sbc8240_part_banks[0].type = "static image";
- sbc8240_part_banks[0].nums = ARRAY_SIZE(sbc8240_uboot_partitions);
- sbc8240_part_banks[1].mtd_part = sbc8240_fs_partitions;
- sbc8240_part_banks[1].type = "static file system";
- sbc8240_part_banks[1].nums = ARRAY_SIZE(sbc8240_fs_partitions);
-
- for (i = 0; i < NUM_FLASH_BANKS; i++) {
-
- if (!sbc8240_mtd[i]) continue;
- if (sbc8240_part_banks[i].nums == 0) {
- printk (KERN_NOTICE MSG_PREFIX
- "No partition info available, registering whole device\n");
- add_mtd_device(sbc8240_mtd[i]);
- } else {
- printk (KERN_NOTICE MSG_PREFIX
- "Using %s partition definition\n", sbc8240_part_banks[i].mtd_part->name);
- add_mtd_partitions (sbc8240_mtd[i],
- sbc8240_part_banks[i].mtd_part,
- sbc8240_part_banks[i].nums);
- }
- }
-#else
- printk(KERN_NOTICE MSG_PREFIX
- "Registering %d flash banks at once\n", devicesfound);
-
- for (i = 0; i < devicesfound; i++) {
- add_mtd_device(sbc8240_mtd[i]);
- }
-#endif /* CONFIG_MTD_PARTITIONS */
-
- return devicesfound == 0 ? -ENXIO : 0;
-}
-
-static void __exit cleanup_sbc8240_mtd (void)
-{
- int i;
-
- for (i = 0; i < NUM_FLASH_BANKS; i++) {
- if (sbc8240_mtd[i]) {
- del_mtd_device (sbc8240_mtd[i]);
- map_destroy (sbc8240_mtd[i]);
- }
- if (sbc8240_map[i].map_priv_1) {
- iounmap ((void *) sbc8240_map[i].map_priv_1);
- sbc8240_map[i].map_priv_1 = 0;
- }
- }
-}
-
-module_init (init_sbc8240_mtd);
-module_exit (cleanup_sbc8240_mtd);
-
-MODULE_LICENSE ("GPL");
-MODULE_AUTHOR ("Carolyn Smith <carolyn.smith@tektronix.com>");
-MODULE_DESCRIPTION ("MTD map driver for SBC8240 boards");
-
---
Regards--
Subrata
^ permalink raw reply
* [PATCH] sky2: Fix checksum endianness
From: Anton Vorontsov @ 2009-06-26 14:51 UTC (permalink / raw)
To: David Miller; +Cc: netdev, Stephen Hemminger, linux-kernel, linuxppc-dev
sky2 driver on PowerPC targets floods kernel log with following errors:
eth1: hw csum failure.
Call Trace:
[ef84b8a0] [c00075e4] show_stack+0x50/0x160 (unreliable)
[ef84b8d0] [c02fa178] netdev_rx_csum_fault+0x3c/0x5c
[ef84b8f0] [c02f6920] __skb_checksum_complete_head+0x7c/0x84
[ef84b900] [c02f693c] __skb_checksum_complete+0x14/0x24
[ef84b910] [c0337e08] tcp_v4_rcv+0x4c8/0x6f8
[ef84b940] [c031a9c8] ip_local_deliver+0x98/0x210
[ef84b960] [c031a788] ip_rcv+0x38c/0x534
[ef84b990] [c0300338] netif_receive_skb+0x260/0x36c
[ef84b9c0] [c025de00] sky2_poll+0x5dc/0xcf8
[ef84ba20] [c02fb7fc] net_rx_action+0xc0/0x144
The NIC is Yukon-2 EC chip revision 1.
Converting checksum field from le16 to CPU byte order fixes the issue.
Signed-off-by: Anton Vorontsov <avorontsov@ru.mvista.com>
---
drivers/net/sky2.c | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c
index 7681d28..daf961a 100644
--- a/drivers/net/sky2.c
+++ b/drivers/net/sky2.c
@@ -2495,7 +2495,7 @@ static int sky2_status_intr(struct sky2_hw *hw, int to_do, u16 idx)
if (likely(status >> 16 == (status & 0xffff))) {
skb = sky2->rx_ring[sky2->rx_next].skb;
skb->ip_summed = CHECKSUM_COMPLETE;
- skb->csum = status & 0xffff;
+ skb->csum = le16_to_cpu(status);
} else {
printk(KERN_NOTICE PFX "%s: hardware receive "
"checksum problem (status = %#x)\n",
--
1.6.3.1
^ permalink raw reply related
* Re: [Bugme-new] [Bug 13304] New: ehci_hcd module causing problems in using usb head phone
From: Alan Stern @ 2009-06-26 15:54 UTC (permalink / raw)
To: abhishekkumar; +Cc: linuxppc-dev, USB list, bugme-daemon
In-Reply-To: <4A44CB89.8040802@tataelxsi.co.in>
On Fri, 26 Jun 2009, abhishekkumar wrote:
> PFA I am attaching dmesg file taken from /var/log/ and also the lines
> which I got from dmesg command in different file named dmesgafter.txt.
I still don't see any lines about the headphone device in the log.
Was the headphone plugged in during boot, or did you plug it in later?
> Then , periodic and registers files and also the usbmon log.
Here's what your "registers" file says:
> bus ps3_system_bus, device sb_05 (driver 10 Dec 2004)
> PS3 EHCI Host Controller
> EHCI ff.ff, hcd state 1
> structural params 0xffffffff
> capability params 0xffffffff
> status ffffffff Async Periodic Recl Halt IAA FATAL FLR PCD ERR INT
> command ffffffff park=3 ithresh=63 LReset IAAD Async Periodic period=?? Reset R
> intrenable ffffffff IAA FATAL FLR PCD ERR INT
> uframe ffffffff
> port 1 status ffffffff POWER OWNER sig=? RESET SUSPEND RESUME OCC OC PEC PE CSC
> port 2 status ffffffff POWER OWNER sig=? RESET SUSPEND RESUME OCC OC PEC PE CSC
> irq normal 30832 err 30 reclaim 84 (lost 1)
> complete 31221 unlink 10
This is very bad. It indicates that the CPU was unable to communicate
with the EHCI controller at all! All the memory-mapped I/O reads
returned 0xffffffff. No wonder the keyboard and mouse stopped working.
I have no idea what could have caused this to happen. Even if the
controller had suffered a fatal error, you wouldn't see this. It looks
like the bus's connection to the controller was turned off.
I'm CC-ing the PS3 maintainer and mailing list. Maybe people there can
help.
> I am even not able to kill the application because it's not showing when
> I use top command.
>
> I addition to that I get some messages during boot up . they are
> Unable to accept address for port 1 (error -62)
> usb cable may be bad
> Unable to accept address for port 2 (error -62)
Those are normal. They occur because your system loads ohci-hcd before
ehci-hcd. It should load ehci-hcd first.
Alan Stern
^ permalink raw reply
* Trouble "Transferring control to Linux (at address 00000000)"
From: Mikhail Zaturenskiy @ 2009-06-26 16:13 UTC (permalink / raw)
To: linuxppc-dev
Hello,
I'm trying to load Linux from U-Boot. I am using ELDK 4.2 with U-Boot
2009.03 on an EP88xC rev1.1 board (MPC885 cpu, 64MB RAM, 32MB FLASH).
The linux kernel sources were obtained from instructions at
"http://www.denx.de/wiki/view/DULG/LinuxConfiguration#Section_6.1."
and the FDT blob (dtb) was generated from
"linux-2.6-denx/arch/powerpc/boot/dts/ep88xc.dts". Below is my output
from boot to hang:
U-Boot 2009.03-svn8591 (Jun 25 2009 - 11:08:09)
CPU: MPC885ZPnn at 100 MHz [40.0...133.0 MHz]
8 kB I-Cache 8 kB D-Cache FEC present
clock 100000000Hz != 300000Hz
Board: EP88xC 1.1 CPLD revision 2
DRAM: 64 MB
Top of RAM usable for U-Boot at: 04000000
Reserving 208k for U-Boot at: 03fcb000
Reserving 384k for malloc() at: 03f6b000
Reserving 60 Bytes for Board Info at: 03f6afc4
Reserving 56 Bytes for Global Data at: 03f6af8c
Stack Pointer at: 03f6af68
New Stack Pointer is: 03f6af68
Now running in RAM - U-Boot at: 03fcb000
FLASH: flash detect cfi
fwc addr fc000000 cmd f0 f0 8bit x 8 bit
...
... <some output skipped> ...
...
is= cmd 59(Y) addr fc000048 is= 00590059 00590059
device interface is 2
found port 4 chip 2 port 32 bits chip 16 bits
00 : 51 52 59 02 00 40 00 00 00 00 00 27 36 00 00 07 QRY..@.....'6...
...
... <some output skipped> ...
...
fwc addr fc000154 cmd 98 00980098 32bit x 16 bit
manufacturer is 2
manufacturer id is 0x1
device id is 0x227e
device id2 is 0x0
cfi version is 0x3133
size_ratio 2 port 32 bits chip 16 bits
found 1 erase regions
erase region 0: 0x0200007f
erase_region_count = 128 erase_region_size = 131072
fwc addr fc000000 cmd f0 00f000f0 32bit x 16 bit
flash_protect ON: from 0xFC000000 to 0xFC02DFFF
protect on 0
flash_protect ON: from 0xFC040000 to 0xFC07FFFF
protect on 1
32 MB
*** Warning - bad CRC, using default environment
In: serial
Out: serial
Err: serial
U-Boot relocated to 03fcb000
Net: FEC ETHERNET, FEC2 ETHERNET
### main_loop entered: bootdelay=2
### main_loop: bootcmd="bootm fc080000"
Hit any key to stop autoboot: 0
## Current stack ends at 0x03f6ad50
* kernel: cmdline image address = 0xfc080000
Wrong Image Format for bootm command
ERROR: can't get kernel image!
=> setenv ipaddr 10.0.54.150
=> setenv serverip 10.0.54.129
=> setenv bootargs root=/dev/ram0 rw
=> setenv ethaddr 00-e0-86-0c-84-fd
eth_set_enetaddr(num=0, addr=00-e0-86-0c-84-fd)
Setting new HW address on FEC ETHERNET
New Address is 00:E0:86:0C:84:FD
eth_set_enetaddr(num=0, addr=00-e0-86-0c-84-fd)
Setting new HW address on FEC ETHERNET
New Address is 00:E0:86:0C:84:FD
=> tftp 400000 ep88x_uimage2
Trying FEC ETHERNET
Using FEC ETHERNET device
TFTP from server 10.0.54.129; our IP address is 10.0.54.150
Filename 'ep88x_uimage2'.
Load address: 0x400000
Loading: #################################################################
########
done
Bytes transferred = 1061544 (1032a8 hex)
=> tftp 550000 ep88x_ramdisk3
Trying FEC ETHERNET
Using FEC ETHERNET device
TFTP from server 10.0.54.129; our IP address is 10.0.54.150
Filename 'ep88x_ramdisk3'.
Load address: 0x550000
Loading: #################################################################
#############################################################
done
Bytes transferred = 1846099 (1c2b53 hex)
=> tftp 750000 ep88x_dtb
Trying FEC ETHERNET
Using FEC ETHERNET device
TFTP from server 10.0.54.129; our IP address is 10.0.54.150
Filename 'ep88x_dtb'.
Load address: 0x750000
Loading: #
done
Bytes transferred = 12288 (3000 hex)
=> bootm 400000 550000 750000
## Current stack ends at 0x03f6ad60
* kernel: cmdline image address = 0x00400000
## Booting kernel from Legacy Image at 00400000 ...
Image Name: Linux-2.6.30-rc2-01402-gd4e2f68-
Image Type: PowerPC Linux Kernel Image (gzip compressed)
Data Size: 1061480 Bytes = 1 MB
Load Address: 00000000
Entry Point: 00000000
Entry Point: 00000000
kernel data at 0x00400040, len = 0x00103268 (1061480)
* ramdisk: cmdline image address = 0x00550000
## Loading init Ramdisk from Legacy Image at 00550000 ...
Image Name: Simple Embedded Linux Framework
Image Type: PowerPC Linux RAMDisk Image (gzip compressed)
Data Size: 1846035 Bytes = 1.8 MB
Load Address: 00000000
Entry Point: 00000000
Verifying Checksum ... OK
ramdisk start = 0x00550040, ramdisk end = 0x00712b53
* fdt: cmdline image address = 0x00750000
## Checking for 'FDT'/'FDT Image' at 00750000
* fdt: raw FDT blob
## Flattened Device Tree blob at 00750000
Booting using the fdt blob at 0x750000
of_flat_tree at 0x00750000 size 0x00003000
Uncompressing Kernel Image ... OK
kernel loaded at 0x00000000, end = 0x00226224
## initrd_high = 0xffffffff, copy_to_ram = 1
Loading Ramdisk to 03da7000, end 03f69b13 ... OK
ramdisk load start = 0x03da7000, ramdisk load end = 0x03f69b13
## Transferring control to Linux (at address 00000000) ...
Booting using OF flat tree...
I did a post-mortem analysis
(http://www.denx.de/wiki/view/DULG/LinuxPostMortemAnalysis) and came
up with the following message:
<6>Using Embedded Planet EP88xC machine description.
<0>Kernel panic - not syncing: Error: Failed to allocate 0x1
................0x800000..
<0>.
<4>Call Trace:.
<4>................69e0]
show_stack...............................21f00] [c001bcb4]
panic+0x8c/0x1................ [c01fac70] lmb_alloc+0x0/0xc.
<4>[c0221f70] [c01................_page+0x60/0x74.
<4>[c0221f80] [c01a4484] pte_alloc_one_kernel+0x
I'm not quite sure where to go from here to get linux working. Anybody
have any suggestions?
Thank you,
Mikhail Zaturenskiy
^ permalink raw reply
* Re: Subject: [PATCH v7] spi: Add PPC4xx SPI driver
From: Steven A. Falco @ 2009-06-26 16:17 UTC (permalink / raw)
Cc: linuxppc-dev@ozlabs.org, Stefan Roese
In-Reply-To: <200906252104.46189.david-b@pacbell.net>
David Brownell wrote:
> On Thursday 25 June 2009, Steven A. Falco wrote:
>> + if (spi->mode & ~MODEBITS) {
>> + dev_dbg(&spi->dev, "setup: unsupported mode bits %x\n",
>> + spi->mode & ~MODEBITS);
>> + return -EINVAL;
>> + }
>
> This wasn't tested against 2.6.30-rc1 was it?
>
I tested against Ben's "next" branch, plus your fix for bitbang_work.
But the new version I'll post is tested against Linus' master branch
(2.6.31-rc1) to take advantage of your mode_bits addition. If you need
this driver to be based on something else, please say so.
> See the recent fixup patch I sent. There's a spi_master->modebits
> mask that should have been initialized, and which eliminates the
> need for tests like that ...
>
Done.
>> + dev_dbg(&spi->dev, "%s: mode %d, %u bpw, %d hz\n",
>> + __func__, spi->mode, spi->bits_per_word,
>> + spi->max_speed_hz);
>> +
>
> ... also the SPI core now provides a *standard* format debug
> message for that stuff. It also handles one more thing, which
> I expect to see fixed in a v8 of this patch ... :)
Ok - I removed that dev_dbg(). Also, I noticed that spi_setup sets
bits_per_word to 8, so I've removed that as well. Did I pass your
test? :-)
Version 8 will follow shortly. BTW, this driver is dependent on your
bitbang_work fix. Not sure if that means it should be added via your
tree. But since we are in an rc phase, I'm guessing this won't merge
until 2.6.32, by which time your fix should be in the mainline.
Steve
^ permalink raw reply
* Subject: [PATCH v8] spi: Add PPC4xx SPI driver
From: Steven A. Falco @ 2009-06-26 16:24 UTC (permalink / raw)
To: David Brownell, Stefan Roese, linuxppc-dev@ozlabs.org
This adds a SPI driver for the SPI controller found in the IBM/AMCC
4xx PowerPC's.
Signed-off-by: Stefan Roese <sr@denx.de>
Signed-off-by: Wolfgang Ocker <weo@reccoware.de>
Acked-by: Josh Boyer <jwboyer@linux.vnet.ibm.com>
Signed-off-by: Steven A. Falco <sfalco@harris.com>
---
Changes in v8:
- Removed redundant dbg messages
- Using new master->mode_line variable
- Removed redundant test and assignment of bits_per_word
- Some white-space fixes from checkpatch
Changes in v7:
- Additional comments as per David Brownell's review
- Corrected phase in mode 2 and 3
- Corrected speed and bits_per_word logic in spi_ppc4xx_setupxfer
- Removed extraneous tests as per David's review
- Added support for "holes" in the chip-select list
- Using dynamic bus allocation
- Corrected initialization logic
Changes in v6:
- Moved comment about high interrupt load to top of file and extended it
by explaining that the 4xx SPI controller has no FIFOs.
- Added parameter checking to setup() routine.
- Removed comment about LSB
- Used of_gpio_count() instead creating own static implementation as
suggested by Anton.
Changes in v5:
- Don't call setupxfer() from setup() so that the baudrate etc
won't get changed while another transfer is active, as suggested
by David Brownell.
- module_{init,exit} moved directly to the functions to which they
apply.
- Use __func__ instead of __FUNCTION__.
Changes in v4:
- Added fixes suggested by Josh Boyer
- Changed compatible property from "ibm,spi" to "ibm,ppc4xx-spi"
Changes in v3:
- When the device is removed the GPIOs are released. The memory
for the GPIO array is freed.
Changes in v2:
- Now the gpios property is correctly decoded and the
resulting gpio numbers are used as the devices chip
selects.
drivers/spi/Kconfig | 7 +
drivers/spi/Makefile | 1 +
drivers/spi/spi_ppc4xx.c | 612 ++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 620 insertions(+), 0 deletions(-)
create mode 100644 drivers/spi/spi_ppc4xx.c
diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
index 2c733c2..1dd9f94 100644
--- a/drivers/spi/Kconfig
+++ b/drivers/spi/Kconfig
@@ -178,6 +178,13 @@ config SPI_PL022
controller. If you have an embedded system with an AMBA(R)
bus and a PL022 controller, say Y or M here.
+config SPI_PPC4xx
+ tristate "PPC4xx SPI Controller"
+ depends on 4xx && SPI_MASTER
+ select SPI_BITBANG
+ help
+ This selects a driver for the PPC4xx SPI Controller.
+
config SPI_PXA2XX
tristate "PXA2xx SSP SPI master"
depends on ARCH_PXA && EXPERIMENTAL
diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile
index 3de408d..cc9a420 100644
--- a/drivers/spi/Makefile
+++ b/drivers/spi/Makefile
@@ -26,6 +26,7 @@ obj-$(CONFIG_SPI_ORION) += orion_spi.o
obj-$(CONFIG_SPI_PL022) += amba-pl022.o
obj-$(CONFIG_SPI_MPC52xx_PSC) += mpc52xx_psc_spi.o
obj-$(CONFIG_SPI_MPC8xxx) += spi_mpc8xxx.o
+obj-$(CONFIG_SPI_PPC4xx) += spi_ppc4xx.o
obj-$(CONFIG_SPI_S3C24XX_GPIO) += spi_s3c24xx_gpio.o
obj-$(CONFIG_SPI_S3C24XX) += spi_s3c24xx.o
obj-$(CONFIG_SPI_TXX9) += spi_txx9.o
diff --git a/drivers/spi/spi_ppc4xx.c b/drivers/spi/spi_ppc4xx.c
new file mode 100644
index 0000000..140a18d
--- /dev/null
+++ b/drivers/spi/spi_ppc4xx.c
@@ -0,0 +1,612 @@
+/*
+ * SPI_PPC4XX SPI controller driver.
+ *
+ * Copyright (C) 2007 Gary Jennejohn <garyj@denx.de>
+ * Copyright 2008 Stefan Roese <sr@denx.de>, DENX Software Engineering
+ * Copyright 2009 Harris Corporation, Steven A. Falco <sfalco@harris.com>
+ *
+ * Based in part on drivers/spi/spi_s3c24xx.c
+ *
+ * Copyright (c) 2006 Ben Dooks
+ * Copyright (c) 2006 Simtec Electronics
+ * Ben Dooks <ben@simtec.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ */
+
+/*
+ * The PPC4xx SPI controller has no FIFO so each sent/received byte will
+ * generate an interrupt to the CPU. This can cause high CPU utilization.
+ * This driver allows platforms to reduce the interrupt load on the CPU
+ * during SPI transfers by setting max_speed_hz via the device tree.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/wait.h>
+#include <linux/of_platform.h>
+#include <linux/of_spi.h>
+#include <linux/of_gpio.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+
+#include <linux/gpio.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/spi_bitbang.h>
+
+#include <asm/io.h>
+#include <asm/dcr.h>
+#include <asm/dcr-regs.h>
+
+/* bits in mode register - bit 0 is MSb */
+
+/*
+ * SPI_PPC4XX_MODE_SCP = 0 means "data latched on trailing edge of clock"
+ * SPI_PPC4XX_MODE_SCP = 1 means "data latched on leading edge of clock"
+ * Note: This is the inverse of CPHA.
+ */
+#define SPI_PPC4XX_MODE_SCP (0x80 >> 3)
+
+/* SPI_PPC4XX_MODE_SPE = 1 means "port enabled" */
+#define SPI_PPC4XX_MODE_SPE (0x80 >> 4)
+
+/*
+ * SPI_PPC4XX_MODE_RD = 0 means "MSB first" - this is the normal mode
+ * SPI_PPC4XX_MODE_RD = 1 means "LSB first" - this is bit-reversed mode
+ * Note: This is identical to SPI_LSB_FIRST.
+ */
+#define SPI_PPC4XX_MODE_RD (0x80 >> 5)
+
+/*
+ * SPI_PPC4XX_MODE_CI = 0 means "clock idles low"
+ * SPI_PPC4XX_MODE_CI = 1 means "clock idles high"
+ * Note: This is identical to CPOL.
+ */
+#define SPI_PPC4XX_MODE_CI (0x80 >> 6)
+
+/*
+ * SPI_PPC4XX_MODE_IL = 0 means "loopback disable"
+ * SPI_PPC4XX_MODE_IL = 1 means "loopback enable"
+ */
+#define SPI_PPC4XX_MODE_IL (0x80 >> 7)
+
+/* bits in control register */
+/* starts a transfer when set */
+#define SPI_PPC4XX_CR_STR (0x80 >> 7)
+
+/* bits in status register */
+/* port is busy with a transfer */
+#define SPI_PPC4XX_SR_BSY (0x80 >> 6)
+/* RxD ready */
+#define SPI_PPC4XX_SR_RBR (0x80 >> 7)
+
+/* clock settings (SCP and CI) for various SPI modes */
+#define SPI_CLK_MODE0 (SPI_PPC4XX_MODE_SCP | 0)
+#define SPI_CLK_MODE1 (0 | 0)
+#define SPI_CLK_MODE2 (SPI_PPC4XX_MODE_SCP | SPI_PPC4XX_MODE_CI)
+#define SPI_CLK_MODE3 (0 | SPI_PPC4XX_MODE_CI)
+
+#define DRIVER_NAME "spi_ppc4xx_of"
+
+struct spi_ppc4xx_regs {
+ u8 mode;
+ u8 rxd;
+ u8 txd;
+ u8 cr;
+ u8 sr;
+ u8 dummy;
+ /*
+ * Clock divisor modulus register
+ * This uses the follwing formula:
+ * SCPClkOut = OPBCLK/(4(CDM + 1))
+ * or
+ * CDM = (OPBCLK/4*SCPClkOut) - 1
+ * bit 0 is the MSb!
+ */
+ u8 cdm;
+};
+
+/* SPI Controller driver's private data. */
+struct ppc4xx_spi {
+ /* bitbang has to be first */
+ struct spi_bitbang bitbang;
+ struct completion done;
+
+ u64 mapbase;
+ u64 mapsize;
+ int irqnum;
+ /* need this to set the SPI clock */
+ unsigned int opb_freq;
+
+ /* for transfers */
+ int len;
+ int count;
+ /* data buffers */
+ const unsigned char *tx;
+ unsigned char *rx;
+
+ int *gpios;
+
+ struct spi_ppc4xx_regs __iomem *regs; /* pointer to the registers */
+ struct spi_master *master;
+ struct device *dev;
+};
+
+/* need this so we can set the clock in the chipselect routine */
+struct spi_ppc4xx_cs {
+ u8 mode;
+};
+
+static int spi_ppc4xx_txrx(struct spi_device *spi, struct spi_transfer *t)
+{
+ struct ppc4xx_spi *hw;
+ u8 data;
+
+ dev_dbg(&spi->dev, "txrx: tx %p, rx %p, len %d\n",
+ t->tx_buf, t->rx_buf, t->len);
+
+ hw = spi_master_get_devdata(spi->master);
+
+ hw->tx = t->tx_buf;
+ hw->rx = t->rx_buf;
+ hw->len = t->len;
+ hw->count = 0;
+
+ /* send the first byte */
+ data = hw->tx ? hw->tx[0] : 0;
+ out_8(&hw->regs->txd, data);
+ out_8(&hw->regs->cr, SPI_PPC4XX_CR_STR);
+ wait_for_completion(&hw->done);
+
+ return hw->count;
+}
+
+static int spi_ppc4xx_setupxfer(struct spi_device *spi, struct spi_transfer *t)
+{
+ struct ppc4xx_spi *hw = spi_master_get_devdata(spi->master);
+ struct spi_ppc4xx_cs *cs = spi->controller_state;
+ int scr;
+ u8 cdm = 0;
+ u32 speed;
+ u8 bits_per_word;
+
+ /* Start with the generic configuration for this device. */
+ bits_per_word = spi->bits_per_word;
+ speed = spi->max_speed_hz;
+
+ /*
+ * Modify the configuration if the transfer overrides it. Do not allow
+ * the transfer to overwrite the generic configuration with zeros.
+ */
+ if (t) {
+ if (t->bits_per_word)
+ bits_per_word = t->bits_per_word;
+
+ if (t->speed_hz)
+ speed = min(t->speed_hz, spi->max_speed_hz);
+ }
+
+ if (bits_per_word != 8) {
+ dev_err(&spi->dev, "invalid bits-per-word (%d)\n",
+ bits_per_word);
+ return -EINVAL;
+ }
+
+ if (!speed || (speed > spi->max_speed_hz)) {
+ dev_err(&spi->dev, "invalid speed_hz (%d)\n", speed);
+ return -EINVAL;
+ }
+
+ /* Write new configration */
+ out_8(&hw->regs->mode, cs->mode);
+
+ /* Set the clock */
+ /* opb_freq was already divided by 4 */
+ scr = (hw->opb_freq / speed) - 1;
+ if (scr > 0)
+ cdm = min(scr, 0xff);
+
+ dev_dbg(&spi->dev, "setting pre-scaler to %d (hz %d)\n", cdm, speed);
+
+ if (in_8(&hw->regs->cdm) != cdm)
+ out_8(&hw->regs->cdm, cdm);
+
+ spin_lock(&hw->bitbang.lock);
+ if (!hw->bitbang.busy) {
+ hw->bitbang.chipselect(spi, BITBANG_CS_INACTIVE);
+ /* Need to ndelay here? */
+ }
+ spin_unlock(&hw->bitbang.lock);
+
+ return 0;
+}
+
+static int spi_ppc4xx_setup(struct spi_device *spi)
+{
+ struct spi_ppc4xx_cs *cs = spi->controller_state;
+
+ if (spi->bits_per_word != 8) {
+ dev_err(&spi->dev, "invalid bits-per-word (%d)\n",
+ spi->bits_per_word);
+ return -EINVAL;
+ }
+
+ if (!spi->max_speed_hz) {
+ dev_err(&spi->dev, "invalid max_speed_hz (must be non-zero)\n");
+ return -EINVAL;
+ }
+
+ if (cs == NULL) {
+ cs = kzalloc(sizeof *cs, GFP_KERNEL);
+ if (!cs)
+ return -ENOMEM;
+ spi->controller_state = cs;
+ }
+
+ /*
+ * We set all bits of the SPI0_MODE register, so,
+ * no need to read-modify-write
+ */
+ cs->mode = SPI_PPC4XX_MODE_SPE;
+
+ switch (spi->mode & (SPI_CPHA | SPI_CPOL)) {
+ case SPI_MODE_0:
+ cs->mode |= SPI_CLK_MODE0;
+ break;
+ case SPI_MODE_1:
+ cs->mode |= SPI_CLK_MODE1;
+ break;
+ case SPI_MODE_2:
+ cs->mode |= SPI_CLK_MODE2;
+ break;
+ case SPI_MODE_3:
+ cs->mode |= SPI_CLK_MODE3;
+ break;
+ }
+
+ if (spi->mode & SPI_LSB_FIRST)
+ cs->mode |= SPI_PPC4XX_MODE_RD;
+
+ return 0;
+}
+
+static void spi_ppc4xx_chipsel(struct spi_device *spi, int value)
+{
+ struct ppc4xx_spi *hw = spi_master_get_devdata(spi->master);
+ unsigned int cs = spi->chip_select;
+ unsigned int cspol;
+
+ /*
+ * If there are no chip selects at all, or if this is the special
+ * case of a non-existent (dummy) chip select, do nothing.
+ */
+
+ if (!hw->master->num_chipselect || hw->gpios[cs] == -EEXIST)
+ return;
+
+ cspol = spi->mode & SPI_CS_HIGH ? 1 : 0;
+ if (value == BITBANG_CS_INACTIVE)
+ cspol = !cspol;
+
+ gpio_set_value(hw->gpios[cs], cspol);
+}
+
+static irqreturn_t spi_ppc4xx_int(int irq, void *dev_id)
+{
+ struct ppc4xx_spi *hw;
+ u8 status;
+ u8 data;
+ unsigned int count;
+
+ hw = (struct ppc4xx_spi *)dev_id;
+
+ status = in_8(&hw->regs->sr);
+ if (!status)
+ return IRQ_NONE;
+
+ /*
+ * BSY de-asserts one cycle after the transfer is complete. The
+ * interrupt is asserted after the transfer is complete. The exact
+ * relationship is not documented, hence this code.
+ */
+
+ if (unlikely(status & SPI_PPC4XX_SR_BSY)) {
+ u8 lstatus;
+ int cnt = 0;
+
+ dev_dbg(hw->dev, "got interrupt but spi still busy?\n");
+ do {
+ ndelay(10);
+ lstatus = in_8(&hw->regs->sr);
+ } while (++cnt < 100 && lstatus & SPI_PPC4XX_SR_BSY);
+
+ if (cnt >= 100) {
+ dev_err(hw->dev, "busywait: too many loops!\n");
+ complete(&hw->done);
+ return IRQ_HANDLED;
+ } else {
+ /* status is always 1 (RBR) here */
+ status = in_8(&hw->regs->sr);
+ dev_dbg(hw->dev, "loops %d status %x\n", cnt, status);
+ }
+ }
+
+ count = hw->count;
+ hw->count++;
+
+ /* RBR triggered this interrupt. Therefore, data must be ready. */
+ data = in_8(&hw->regs->rxd);
+ if (hw->rx)
+ hw->rx[count] = data;
+
+ count++;
+
+ if (count < hw->len) {
+ data = hw->tx ? hw->tx[count] : 0;
+ out_8(&hw->regs->txd, data);
+ out_8(&hw->regs->cr, SPI_PPC4XX_CR_STR);
+ } else {
+ complete(&hw->done);
+ }
+
+ return IRQ_HANDLED;
+}
+
+static void spi_ppc4xx_cleanup(struct spi_device *spi)
+{
+ kfree(spi->controller_state);
+}
+
+static void spi_ppc4xx_enable(struct ppc4xx_spi *hw)
+{
+ /*
+ * On all 4xx PPC's the SPI bus is shared/multiplexed with
+ * the 2nd I2C bus. We need to enable the the SPI bus before
+ * using it.
+ */
+
+ /* need to clear bit 14 to enable SPC */
+ dcri_clrset(SDR0, SDR0_PFC1, 0x80000000 >> 14, 0);
+}
+
+static void free_gpios(struct ppc4xx_spi *hw)
+{
+ if (hw->master->num_chipselect) {
+ int i;
+ for (i = 0; i < hw->master->num_chipselect; i++)
+ if (gpio_is_valid(hw->gpios[i]))
+ gpio_free(hw->gpios[i]);
+
+ kfree(hw->gpios);
+ hw->gpios = NULL;
+ }
+}
+
+/*
+ * of_device layer stuff...
+ */
+static int __init spi_ppc4xx_of_probe(struct of_device *op,
+ const struct of_device_id *match)
+{
+ struct ppc4xx_spi *hw;
+ struct spi_master *master;
+ struct spi_bitbang *bbp;
+ struct resource resource;
+ struct device_node *np = op->node;
+ struct device *dev = &op->dev;
+ struct device_node *opbnp;
+ int ret;
+ int num_gpios;
+ const unsigned int *clk;
+
+ master = spi_alloc_master(dev, sizeof *hw);
+ if (master == NULL)
+ return -ENOMEM;
+ dev_set_drvdata(dev, master);
+ hw = spi_master_get_devdata(master);
+ hw->master = spi_master_get(master);
+ hw->dev = dev;
+
+ init_completion(&hw->done);
+
+ /*
+ * A count of zero implies a single SPI device without any chip-select.
+ * Note that of_gpio_count counts all gpios assigned to this spi master.
+ * This includes both "null" gpio's and real ones.
+ */
+ num_gpios = of_gpio_count(np);
+ if (num_gpios) {
+ int i;
+
+ hw->gpios = kzalloc(sizeof(int) * num_gpios, GFP_KERNEL);
+ if (!hw->gpios) {
+ ret = -ENOMEM;
+ goto free_master;
+ }
+
+ for (i = 0; i < num_gpios; i++) {
+ int gpio;
+ enum of_gpio_flags flags;
+
+ gpio = of_get_gpio_flags(np, i, &flags);
+ hw->gpios[i] = gpio;
+
+ if (gpio_is_valid(gpio)) {
+ /* Real CS - set the initial state. */
+ ret = gpio_request(gpio, np->name);
+ if (ret < 0) {
+ dev_err(dev, "can't request gpio "
+ "#%d: %d\n", i, ret);
+ goto free_gpios;
+ }
+
+ gpio_direction_output(gpio,
+ !!(flags & OF_GPIO_ACTIVE_LOW));
+ } else if (gpio == -EEXIST) {
+ ; /* No CS, but that's OK. */
+ } else {
+ dev_err(dev, "invalid gpio #%d: %d\n", i, gpio);
+ ret = -EINVAL;
+ goto free_gpios;
+ }
+ }
+ }
+
+ /* Setup the state for the bitbang driver */
+ bbp = &hw->bitbang;
+ bbp->master = hw->master;
+ bbp->setup_transfer = spi_ppc4xx_setupxfer;
+ bbp->chipselect = spi_ppc4xx_chipsel;
+ bbp->txrx_bufs = spi_ppc4xx_txrx;
+ bbp->use_dma = 0;
+ bbp->master->setup = spi_ppc4xx_setup;
+ bbp->master->cleanup = spi_ppc4xx_cleanup;
+
+ /* Allocate bus num dynamically. */
+ bbp->master->bus_num = -1;
+
+ /* the spi->mode bits understood by this driver: */
+ bbp->master->mode_bits =
+ SPI_CPHA | SPI_CPOL | SPI_CS_HIGH | SPI_LSB_FIRST;
+
+ /* this many pins in all GPIO controllers */
+ bbp->master->num_chipselect = num_gpios;
+
+ /* Get the clock for the OPB */
+ opbnp = of_find_compatible_node(NULL, NULL, "ibm,opb");
+ if (opbnp == NULL) {
+ dev_err(dev, "OPB: cannot find node\n");
+ ret = -ENODEV;
+ goto free_gpios;
+ }
+ /* Get the clock (Hz) for the OPB */
+ clk = of_get_property(opbnp, "clock-frequency", NULL);
+ if (clk == NULL) {
+ dev_err(dev, "OPB: no clock-frequency property set\n");
+ of_node_put(opbnp);
+ ret = -ENODEV;
+ goto free_gpios;
+ }
+ hw->opb_freq = *clk;
+ hw->opb_freq >>= 2;
+ of_node_put(opbnp);
+
+ ret = of_address_to_resource(np, 0, &resource);
+ if (ret) {
+ dev_err(dev, "error while parsing device node resource\n");
+ goto free_gpios;
+ }
+ hw->mapbase = resource.start;
+ hw->mapsize = resource.end - resource.start + 1;
+
+ /* Sanity check */
+ if (hw->mapsize < sizeof(struct spi_ppc4xx_regs)) {
+ dev_err(dev, "too small to map registers\n");
+ ret = -EINVAL;
+ goto free_gpios;
+ }
+
+ /* Request IRQ */
+ hw->irqnum = irq_of_parse_and_map(np, 0);
+ ret = request_irq(hw->irqnum, spi_ppc4xx_int,
+ IRQF_DISABLED, "spi_ppc4xx_of", (void *)hw);
+ if (ret) {
+ dev_err(dev, "unable to allocate interrupt\n");
+ goto free_gpios;
+ }
+
+ if (!request_mem_region(hw->mapbase, hw->mapsize, DRIVER_NAME)) {
+ dev_err(dev, "resource unavailable\n");
+ ret = -EBUSY;
+ goto request_mem_error;
+ }
+
+ hw->regs = ioremap(hw->mapbase, sizeof(struct spi_ppc4xx_regs));
+
+ if (!hw->regs) {
+ dev_err(dev, "unable to memory map registers\n");
+ ret = -ENXIO;
+ goto map_io_error;
+ }
+
+ spi_ppc4xx_enable(hw);
+
+ /* Finally register our spi controller */
+ dev->dma_mask = 0;
+ ret = spi_bitbang_start(bbp);
+ if (ret) {
+ dev_err(dev, "failed to register SPI master\n");
+ goto unmap_regs;
+ }
+
+ dev_info(dev, "driver initialized\n");
+ of_register_spi_devices(master, np);
+
+ return 0;
+
+unmap_regs:
+ iounmap(hw->regs);
+map_io_error:
+ release_mem_region(hw->mapbase, hw->mapsize);
+request_mem_error:
+ free_irq(hw->irqnum, hw);
+free_gpios:
+ free_gpios(hw);
+free_master:
+ dev_set_drvdata(dev, NULL);
+ spi_master_put(master);
+
+ dev_err(dev, "initialization failed\n");
+ return ret;
+}
+
+static int __exit spi_ppc4xx_of_remove(struct of_device *op)
+{
+ struct spi_master *master = dev_get_drvdata(&op->dev);
+ struct ppc4xx_spi *hw = spi_master_get_devdata(master);
+
+ spi_bitbang_stop(&hw->bitbang);
+ dev_set_drvdata(&op->dev, NULL);
+ release_mem_region(hw->mapbase, hw->mapsize);
+ free_irq(hw->irqnum, hw);
+ iounmap(hw->regs);
+ free_gpios(hw);
+ return 0;
+}
+
+static struct of_device_id spi_ppc4xx_of_match[] = {
+ { .compatible = "ibm,ppc4xx-spi", },
+ {},
+};
+
+MODULE_DEVICE_TABLE(of, spi_ppc4xx_of_match);
+
+static struct of_platform_driver spi_ppc4xx_of_driver = {
+ .match_table = spi_ppc4xx_of_match,
+ .probe = spi_ppc4xx_of_probe,
+ .remove = __exit_p(spi_ppc4xx_of_remove),
+ .driver = {
+ .name = DRIVER_NAME,
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init spi_ppc4xx_init(void)
+{
+ return of_register_platform_driver(&spi_ppc4xx_of_driver);
+}
+module_init(spi_ppc4xx_init);
+
+static void __exit spi_ppc4xx_exit(void)
+{
+ of_unregister_platform_driver(&spi_ppc4xx_of_driver);
+}
+module_exit(spi_ppc4xx_exit);
+
+MODULE_AUTHOR("Gary Jennejohn & Stefan Roese");
+MODULE_DESCRIPTION("Simple PPC4xx SPI Driver");
+MODULE_LICENSE("GPL");
--
1.6.0.2
^ permalink raw reply related
* Re: [PATCH] sky2: Fix checksum endianness
From: David Miller @ 2009-06-26 16:28 UTC (permalink / raw)
To: avorontsov; +Cc: netdev, shemminger, linux-kernel, linuxppc-dev
In-Reply-To: <20090626145159.GA2242@oksana.dev.rtsoft.ru>
From: Anton Vorontsov <avorontsov@ru.mvista.com>
Date: Fri, 26 Jun 2009 18:51:59 +0400
> sky2 driver on PowerPC targets floods kernel log with following errors:
>
> eth1: hw csum failure.
> Call Trace:
> [ef84b8a0] [c00075e4] show_stack+0x50/0x160 (unreliable)
> [ef84b8d0] [c02fa178] netdev_rx_csum_fault+0x3c/0x5c
> [ef84b8f0] [c02f6920] __skb_checksum_complete_head+0x7c/0x84
> [ef84b900] [c02f693c] __skb_checksum_complete+0x14/0x24
> [ef84b910] [c0337e08] tcp_v4_rcv+0x4c8/0x6f8
> [ef84b940] [c031a9c8] ip_local_deliver+0x98/0x210
> [ef84b960] [c031a788] ip_rcv+0x38c/0x534
> [ef84b990] [c0300338] netif_receive_skb+0x260/0x36c
> [ef84b9c0] [c025de00] sky2_poll+0x5dc/0xcf8
> [ef84ba20] [c02fb7fc] net_rx_action+0xc0/0x144
>
> The NIC is Yukon-2 EC chip revision 1.
>
> Converting checksum field from le16 to CPU byte order fixes the issue.
>
> Signed-off-by: Anton Vorontsov <avorontsov@ru.mvista.com>
Applied, thank you!
^ 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