* Re: [PATCH RFC 0/3] Implement refcounting for OF GPIO chips
From: Anton Vorontsov @ 2010-02-09 19:06 UTC (permalink / raw)
To: Michal Simek
Cc: Michal Simek, David Brownell, devicetree-discuss, linux-kernel,
linuxppc-dev, microblaze-uclinux, David Miller
In-Reply-To: <4B712DA5.4000802@petalogix.com>
On Tue, Feb 09, 2010 at 10:40:53AM +0100, Michal Simek wrote:
[...]
> >The above situation is hard to trigger, but the issue is there
> >nonetheless, and so needs fixing.
>
>
> I tested xilinx gpio driver, heartbeat trigger and access through
> sysfs and I haven't found any problem. There is only small part of
> code for Microblaze and it is the same with PowerPC. If is Ben OK
> with it, I am ok too.
Thanks for testing!
--
Anton Vorontsov
email: cbouatmailru@gmail.com
irc://irc.freenode.net/bd2
^ permalink raw reply
* Re: [PATCH 3/4] of/gpio: Implement GPIOLIB notifier hooks
From: Anton Vorontsov @ 2010-02-09 19:06 UTC (permalink / raw)
To: Grant Likely
Cc: David Brownell, Dmitry Eremin-Solenikov, linux-kernel,
linuxppc-dev, Bill Gatliff, Andrew Morton
In-Reply-To: <fa686aa41002090908tbeed469k417af2a59757f8a@mail.gmail.com>
On Tue, Feb 09, 2010 at 10:08:00AM -0700, Grant Likely wrote:
> On Fri, Feb 5, 2010 at 1:32 PM, Anton Vorontsov
> <avorontsov@ru.mvista.com> wrote:
> > This patch implements GPIOLIB notifier hooks, and thus makes device-enabled
> > GPIO chips (i.e. the ones that have gpio_chip->dev specified) automatically
> > attached to the OpenFirmware subsystem. Which means that now we can handle
> > I2C and SPI GPIO chips almost* transparently.
[...]
> One concern.
>
> How does an OF-aware GPIO driver override these settings? What is to
> be done when a GPIO chip requires a different xlate hook? Or a
> different number of gpio_cells?
A lot of options...
1. They can hook up onto a notifier chain, ensure that their callback
will be called after OF GPIO subsystem (using notifiers' priority
mechanism), and fixup needed stuff.
2. They can write their own full fledged OF bindings, i.e. they will
need to allocate of_gc struct and save it into np->data.
of_gpiochip_register_simple() won't touch np->data if it's already
used.
If/when needed, we can write some helper function, i.e.
of_gpiochip_register(gpiochip, node, xlate_callback).
3. Or of/gpio.c code will handle this by itself, iff the xlate and
gpio-cells scheme seems generic enough.
4. May be more...
Thanks,
--
Anton Vorontsov
email: cbouatmailru@gmail.com
irc://irc.freenode.net/bd2
^ permalink raw reply
* Re: [PATCH 2/3] of: Introduce safe accessors for node->data
From: Anton Vorontsov @ 2010-02-09 19:10 UTC (permalink / raw)
To: Grant Likely
Cc: Michal Simek, David Brownell, devicetree-discuss, linux-kernel,
linuxppc-dev, microblaze-uclinux, David Miller
In-Reply-To: <fa686aa41002090925q30f362d6x4d14894a72439125@mail.gmail.com>
On Tue, Feb 09, 2010 at 10:25:22AM -0700, Grant Likely wrote:
> On Fri, Feb 5, 2010 at 1:50 PM, Anton Vorontsov
> <avorontsov@ru.mvista.com> wrote:
> > Platform code use node->data to store some private information
> > associated with a node.
> >
> > Previously there was no need for any locks and accessors since we were
> > initializing the data mostly at boot time and never modified it later.
> >
> > Though, nowadays OF GPIO infrastructure supports GPIO chips detaching,
> > so to handle this correctly we have to introduce locking for the
> > node->data field.
>
> I'm not convinced this is needed. What's wrong with using the
> whole-tree devtree_lock?
Why are you concerned? It doesn't add much of any footprint.
$ grep -c { -r arch/powerpc/boot/dts/ | cut -d: -f2 | sort -n | tail -n1
84
So far we have max 84 nodes, so it's a few hundreds of bytes for all
the dev tree.
Anyway, yes, we can use the devtree lock. Though, this will require a
bit more modifications, and I'm not sure if it's a great idea in
general (i.e. using the global lock in contrast to fine grained
locking).
The thing is that you can't use most of the of_ functions when you
hold the devtree lock (IIRC, rwlock has the same restrictions as a
spinlock, so you can't nest these locks).
I can try to rework OF GPIO calls so that they won't require of_
calls when they hold the lock, and let's see how it'll look like.
Thanks!
--
Anton Vorontsov
email: cbouatmailru@gmail.com
irc://irc.freenode.net/bd2
^ permalink raw reply
* Re: [PATCH 3/3] of/gpio: Introduce of_put_gpio(), add ref counting for OF GPIO chips
From: Anton Vorontsov @ 2010-02-09 19:14 UTC (permalink / raw)
To: Grant Likely
Cc: Michal Simek, David Brownell, devicetree-discuss, linux-kernel,
linuxppc-dev, microblaze-uclinux, David Miller
In-Reply-To: <fa686aa41002090928o6911d095ydca1e1e670a0fc22@mail.gmail.com>
On Tue, Feb 09, 2010 at 10:28:15AM -0700, Grant Likely wrote:
[...]
> Rather than having a lock at the device tree data pointer level which
> mixes usage with potentially many other drivers; wouldn't it make more
> sense to use a mutex at the of_gc subsystem context?
I don't think so.
of_gc = np->data;
lock(of_gc); (or lock(devtree))
<do something with of_gc>
doesn't provide us what we need, i.e. it doesn't guarantee that
np->data (of_gc) is still alive.
And here:
lock(np->data); (or lock(devtree))
of_gc = np->data;
lock(of_gc);
<do something with of_gc>
The second lock becomes useless (unless you also refcount np->data
usage and can drop the devtree/np->data lock, and grab some other
kind of lock, e.g. mutex, but this is silly).
Thanks,
--
Anton Vorontsov
email: cbouatmailru@gmail.com
irc://irc.freenode.net/bd2
^ permalink raw reply
* Re: [PATCH 3/4] of/gpio: Implement GPIOLIB notifier hooks
From: Anton Vorontsov @ 2010-02-09 19:16 UTC (permalink / raw)
To: Grant Likely
Cc: David Brownell, Dmitry Eremin-Solenikov, linux-kernel,
linuxppc-dev, Bill Gatliff, Andrew Morton
In-Reply-To: <fa686aa41002090913t4c72a3b8o5fda68723bc8d089@mail.gmail.com>
On Tue, Feb 09, 2010 at 10:13:11AM -0700, Grant Likely wrote:
[...]
> > +static int __init of_gpio_notifier_init(void)
> > +{
> > + return blocking_notifier_chain_register(&gpio_notifier, &of_gpio_nb);
> > +}
> > +arch_initcall(of_gpio_notifier_init);
>
> Another concern; if any gpio chips get registered before this
> arch_initcall (not sure if it is possible or not), then those chips
> won't get registered with the of gpio infrastructure.
Technically, it is possible, but registering usual GPIO controllers
in arch_initcall feels not quite right approach in the first place
(and, btw, it won't work most of the time, because even early drivers
do not register itself earlier than subsys_initcall).
And arch gpio controllers (like QE GPIO) are usually device-less,
and they use of_mm_gpiochip_add(), so we fully control them.
Plus I don't see any reason why we couldn't move
of_gpio_notifier_init() into, say, postcore_initcall, if we ever
need it.
Thanks,
--
Anton Vorontsov
email: cbouatmailru@gmail.com
irc://irc.freenode.net/bd2
^ permalink raw reply
* Re: [PATCH v4 3/3] powerpc: doc/dts-bindings: update doc of FSL I2C bindings
From: Wolfgang Grandegger @ 2010-02-09 19:23 UTC (permalink / raw)
To: Grant Likely
Cc: Wolfgang Grandegger, Devicetree-discuss, Linuxppc-dev, Linux-i2c,
Ben Dooks
In-Reply-To: <4B71AFFC.3010301@grandegger.com>
Wolfgang Grandegger wrote:
> Hi Grant,
>
> Grant Likely wrote:
>> On Thu, Jan 28, 2010 at 6:25 AM, Wolfgang Grandegger <wg@grandegger.com> wrote:
>>> From: Wolfgang Grandegger <wg@denx.de>
>>>
>>> This patch adds the MPC5121 to the list of supported devices,
>>> enhances the doc of the "clock-frequency" property and removes
>>> the obsolete "cell-index" property from the example nodes.
>>> Furthermore and example for the MPC5121 has been added.
>>>
>>> Signed-off-by: Wolfgang Grandegger <wg@denx.de>
>> Thanks Wolfgang. Comments below.
>>
>>> ---
>>> Documentation/powerpc/dts-bindings/fsl/i2c.txt | 30 +++++++++++++++++++----
>>> 1 files changed, 24 insertions(+), 6 deletions(-)
>>>
>>> diff --git a/Documentation/powerpc/dts-bindings/fsl/i2c.txt b/Documentation/powerpc/dts-bindings/fsl/i2c.txt
>>> index b6d2e21..2f62dae 100644
>>> --- a/Documentation/powerpc/dts-bindings/fsl/i2c.txt
>>> +++ b/Documentation/powerpc/dts-bindings/fsl/i2c.txt
>>> @@ -9,8 +9,9 @@ Recommended properties :
>>>
>>> - compatible : compatibility list with 2 entries, the first should
>>> be "fsl,CHIP-i2c" where CHIP is the name of a compatible processor,
>>> - e.g. mpc8313, mpc8543, mpc8544, mpc5200 or mpc5200b. The second one
>>> - should be "fsl-i2c".
>>> + e.g. mpc8313, mpc8543, mpc8544, mpc5121, mpc5200 or mpc5200b. The
>>> + second one should be "fsl-i2c". For the mpc5121, an additional node
>>> + "fsl,mpc5121-i2c-ctrl" is required as shown in the example below.
>> While you're editing this line; drop the requirement for the second
>> value to be 'fsl-i2c'. We don't use it anymore, and only preserve it
>> for backwards compatibility with old trees.
>
> OK.
>
>>> - interrupts : <a b> where a is the interrupt number and b is a
>>> field that represents an encoding of the sense and level
>>> information for the interrupt. This should be encoded based on
>>> @@ -20,29 +21,46 @@ Recommended properties :
>>> services interrupts for this device.
>>> - fsl,preserve-clocking : boolean; if defined, the clock settings
>>> from the bootloader are preserved (not touched).
>>> - - clock-frequency : desired I2C bus clock frequency in Hz.
>>> + - clock-frequency : desired I2C bus clock frequency in Hz. If this
>>> + property and "fsl,preserve-clocking" is not defined, a safe fixed
>>> + clock divider value is used (resulting in a small clock frequency).
>> Nah, leave this as is. Don't make it sound like omitting both
>> properties is a valid option. The driver may (and should!) handle the
>> situation gracefully, but that fact does not need to be documented.
>
> The safe value is not a good choice, indeed. Then it will also change
> MPC_I2C_CLOCK_SAFE to MPC_I2C_CLOCK_LEGACY in i2c-mpc.c.
>
> I will also fix the other issues you commented on.
And I will also remove the "device_type" line from:
-------------
Required properties :
- device_type : Should be "i2c"
- reg : Offset and length of the register set for the device
-------------
Wolfgang.
^ permalink raw reply
* Re: [net-next-2.6 PATCH 2/3] fs_enet: Add support for MPC512x to fs_enet driver
From: David Miller @ 2010-02-09 20:13 UTC (permalink / raw)
To: agust; +Cc: kosmo, dzu, netdev, linuxppc-dev, wd
In-Reply-To: <20100209152317.5303b1b3@wker>
From: Anatolij Gustschin <agust@denx.de>
Date: Tue, 9 Feb 2010 15:23:17 +0100
> In my understanding, in the ESP scsi driver the set of defines for
> the register offsets is common for all chip drivers. The chip driver
> methods for register access translate the offsets because the
> registers on some chips are at different intervals (4-byte, 1-byte,
> 16-byte for mac_esp.c). But the register order is the same for
> different chips.
>
> In our case non only the register order is not the same for 8xx
> FEC and 5121 FEC, but there are also other differences, different
> reserved areas between several registers, some registers are
> available only on 8xx and some only on 5121.
That only means you would need to use a table based register address
translation scheme, rather than a simple calculation. Something
like:
static unsigned int chip_xxx_table[] =
{
[GENERIC_REG_FOO] = CHIP_XXX_FOO,
...
};
static u32 chip_xxx_read_reg(struct chip *p, unsigned int reg)
{
unsigned int reg_off = chip_xxx_table[reg];
return readl(p->regs + reg_off);
}
And this table can have special tokens in entries for
registers which do not exist on a chip, so you can trap
attempted access to them in these read/write handlers.
Please stop looking for excuses to fork this driver, a
unified driver I think can be done cleanly.
^ permalink raw reply
* [PATCH] [V3] net: emaclite: adding MDIO and phy lib support
From: John Linn @ 2010-02-09 20:31 UTC (permalink / raw)
To: netdev, linuxppc-dev, jgarzik, grant.likely, jwboyer
Cc: John Linn, john.williams, Sadanand Mutyala
These changes add MDIO and phy lib support to the driver as the
IP core now supports the MDIO bus.
The MDIO bus and phy are added as a child to the emaclite in the device
tree as illustrated below.
mdio {
#address-cells = <1>;
#size-cells = <0>;
phy0: phy@7 {
compatible = "marvell,88e1111";
reg = <7>;
} ;
}
Signed-off-by: Sadanand Mutyala <Sadanand.Mutyala@xilinx.com>
Signed-off-by: John Linn <john.linn@xilinx.com>
Acked-by: Grant Likely <grant.likely@secretlab.ca>
---
V2 - updated it for Grant's comments, except I couldn't find any tabs
converted to white space issue, let's see if V2 has it also
V3 - updated it for Grant's comments, aded mutex release when a timeout
happens, and added Grant's acked by.
---
drivers/net/Kconfig | 1 +
drivers/net/xilinx_emaclite.c | 399 ++++++++++++++++++++++++++++++++++++-----
2 files changed, 357 insertions(+), 43 deletions(-)
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index dd9a09c..9509a36 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -1939,6 +1939,7 @@ config ATL2
config XILINX_EMACLITE
tristate "Xilinx 10/100 Ethernet Lite support"
depends on PPC32 || MICROBLAZE
+ select PHYLIB
help
This driver supports the 10/100 Ethernet Lite from Xilinx.
diff --git a/drivers/net/xilinx_emaclite.c b/drivers/net/xilinx_emaclite.c
index 8c777ba..feed72d 100644
--- a/drivers/net/xilinx_emaclite.c
+++ b/drivers/net/xilinx_emaclite.c
@@ -22,11 +22,17 @@
#include <linux/of_device.h>
#include <linux/of_platform.h>
+#include <linux/of_mdio.h>
+#include <linux/phy.h>
#define DRIVER_NAME "xilinx_emaclite"
/* Register offsets for the EmacLite Core */
#define XEL_TXBUFF_OFFSET 0x0 /* Transmit Buffer */
+#define XEL_MDIOADDR_OFFSET 0x07E4 /* MDIO Address Register */
+#define XEL_MDIOWR_OFFSET 0x07E8 /* MDIO Write Data Register */
+#define XEL_MDIORD_OFFSET 0x07EC /* MDIO Read Data Register */
+#define XEL_MDIOCTRL_OFFSET 0x07F0 /* MDIO Control Register */
#define XEL_GIER_OFFSET 0x07F8 /* GIE Register */
#define XEL_TSR_OFFSET 0x07FC /* Tx status */
#define XEL_TPLR_OFFSET 0x07F4 /* Tx packet length */
@@ -37,6 +43,22 @@
#define XEL_BUFFER_OFFSET 0x0800 /* Next Tx/Rx buffer's offset */
+/* MDIO Address Register Bit Masks */
+#define XEL_MDIOADDR_REGADR_MASK 0x0000001F /* Register Address */
+#define XEL_MDIOADDR_PHYADR_MASK 0x000003E0 /* PHY Address */
+#define XEL_MDIOADDR_PHYADR_SHIFT 5
+#define XEL_MDIOADDR_OP_MASK 0x00000400 /* RD/WR Operation */
+
+/* MDIO Write Data Register Bit Masks */
+#define XEL_MDIOWR_WRDATA_MASK 0x0000FFFF /* Data to be Written */
+
+/* MDIO Read Data Register Bit Masks */
+#define XEL_MDIORD_RDDATA_MASK 0x0000FFFF /* Data to be Read */
+
+/* MDIO Control Register Bit Masks */
+#define XEL_MDIOCTRL_MDIOSTS_MASK 0x00000001 /* MDIO Status Mask */
+#define XEL_MDIOCTRL_MDIOEN_MASK 0x00000008 /* MDIO Enable */
+
/* Global Interrupt Enable Register (GIER) Bit Masks */
#define XEL_GIER_GIE_MASK 0x80000000 /* Global Enable */
@@ -87,6 +109,13 @@
* @reset_lock: lock used for synchronization
* @deferred_skb: holds an skb (for transmission at a later time) when the
* Tx buffer is not free
+ * @phy_dev: pointer to the PHY device
+ * @phy_node: pointer to the PHY device node
+ * @mii_bus: pointer to the MII bus
+ * @mdio_irqs: IRQs table for MDIO bus
+ * @last_link: last link status
+ * @has_mdio: indicates whether MDIO is included in the HW
+ * @mdio_mutex: protects MDIO accesses
*/
struct net_local {
@@ -100,6 +129,16 @@ struct net_local {
spinlock_t reset_lock;
struct sk_buff *deferred_skb;
+
+ struct phy_device *phy_dev;
+ struct device_node *phy_node;
+
+ struct mii_bus *mii_bus;
+ int mdio_irqs[PHY_MAX_ADDR];
+
+ int last_link;
+ bool has_mdio;
+ struct mutex mdio_mutex;
};
@@ -431,7 +470,7 @@ static u16 xemaclite_recv_data(struct net_local *drvdata, u8 *data)
}
/**
- * xemaclite_set_mac_address - Set the MAC address for this device
+ * xemaclite_update_address - Update the MAC address in the device
* @drvdata: Pointer to the Emaclite device private data
* @address_ptr:Pointer to the MAC address (MAC address is a 48-bit value)
*
@@ -441,8 +480,8 @@ static u16 xemaclite_recv_data(struct net_local *drvdata, u8 *data)
* The MAC address can be programmed using any of the two transmit
* buffers (if configured).
*/
-static void xemaclite_set_mac_address(struct net_local *drvdata,
- u8 *address_ptr)
+static void xemaclite_update_address(struct net_local *drvdata,
+ u8 *address_ptr)
{
void __iomem *addr;
u32 reg_data;
@@ -465,6 +504,30 @@ static void xemaclite_set_mac_address(struct net_local *drvdata,
}
/**
+ * xemaclite_set_mac_address - Set the MAC address for this device
+ * @dev: Pointer to the network device instance
+ * @addr: Void pointer to the sockaddr structure
+ *
+ * This function copies the HW address from the sockaddr strucutre to the
+ * net_device structure and updates the address in HW.
+ *
+ * Return: Error if the net device is busy or 0 if the addr is set
+ * successfully
+ */
+static int xemaclite_set_mac_address(struct net_device *dev, void *address)
+{
+ struct net_local *lp = (struct net_local *) netdev_priv(dev);
+ struct sockaddr *addr = address;
+
+ if (netif_running(dev))
+ return -EBUSY;
+
+ memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
+ xemaclite_update_address(lp, dev->dev_addr);
+ return 0;
+}
+
+/**
* xemaclite_tx_timeout - Callback for Tx Timeout
* @dev: Pointer to the network device
*
@@ -641,12 +704,234 @@ static irqreturn_t xemaclite_interrupt(int irq, void *dev_id)
return IRQ_HANDLED;
}
+/**********************/
+/* MDIO Bus functions */
+/**********************/
+
+/**
+ * xemaclite_mdio_wait - Wait for the MDIO to be ready to use
+ * @lp: Pointer to the Emaclite device private data
+ *
+ * This function waits till the device is ready to accept a new MDIO
+ * request. Since this function uses msleep, the mdio_mutex is used
+ * to protect MDIO processsing.
+ *
+ * Return: 0 for success or ETIMEDOUT for a timeout
+ */
+
+static int xemaclite_mdio_wait(struct net_local *lp)
+{
+ long end = jiffies + 2;
+
+ /* wait for the MDIO interface to not be busy or timeout
+ after some time.
+ */
+ while (in_be32(lp->base_addr + XEL_MDIOCTRL_OFFSET) &
+ XEL_MDIOCTRL_MDIOSTS_MASK) {
+ if (end - jiffies <= 0) {
+ WARN_ON(1);
+ return -ETIMEDOUT;
+ }
+ msleep(1);
+ }
+ return 0;
+}
+
+/**
+ * xemaclite_mdio_read - Read from a given MII management register
+ * @bus: the mii_bus struct
+ * @phy_id: the phy address
+ * @reg: register number to read from
+ *
+ * This function waits till the device is ready to accept a new MDIO
+ * request and then writes the phy address to the MDIO Address register
+ * and reads data from MDIO Read Data register, when its available.
+ *
+ * Return: Value read from the MII management register
+ */
+static int xemaclite_mdio_read(struct mii_bus *bus, int phy_id, int reg)
+{
+ struct net_local *lp = bus->priv;
+ u32 ctrl_reg;
+ u32 rc;
+
+ mutex_lock(&lp->mdio_mutex);
+
+ if (xemaclite_mdio_wait(lp)) {
+ mutex_unlock(&lp->mdio_mutex);
+ return -ETIMEDOUT;
+ }
+
+ /* Write the PHY address, register number and set the OP bit in the
+ * MDIO Address register. Set the Status bit in the MDIO Control
+ * register to start a MDIO read transaction.
+ */
+ ctrl_reg = in_be32(lp->base_addr + XEL_MDIOCTRL_OFFSET);
+ out_be32(lp->base_addr + XEL_MDIOADDR_OFFSET,
+ XEL_MDIOADDR_OP_MASK |
+ ((phy_id << XEL_MDIOADDR_PHYADR_SHIFT) | reg));
+ out_be32(lp->base_addr + XEL_MDIOCTRL_OFFSET,
+ ctrl_reg | XEL_MDIOCTRL_MDIOSTS_MASK);
+
+ if (xemaclite_mdio_wait(lp)) {
+ mutex_unlock(&lp->mdio_mutex);
+ return -ETIMEDOUT;
+ }
+
+ rc = in_be32(lp->base_addr + XEL_MDIORD_OFFSET);
+
+ mutex_unlock(&lp->mdio_mutex);
+
+ dev_dbg(&lp->ndev->dev,
+ "xemaclite_mdio_read(phy_id=%i, reg=%x) == %x\n",
+ phy_id, reg, rc);
+
+ return rc;
+}
+
+/**
+ * xemaclite_mdio_write - Write to a given MII management register
+ * @bus: the mii_bus struct
+ * @phy_id: the phy address
+ * @reg: register number to write to
+ * @val: value to write to the register number specified by reg
+ *
+ * This fucntion waits till the device is ready to accept a new MDIO
+ * request and then writes the val to the MDIO Write Data register.
+ */
+static int xemaclite_mdio_write(struct mii_bus *bus, int phy_id, int reg,
+ u16 val)
+{
+ struct net_local *lp = bus->priv;
+ u32 ctrl_reg;
+
+ dev_dbg(&lp->ndev->dev,
+ "xemaclite_mdio_write(phy_id=%i, reg=%x, val=%x)\n",
+ phy_id, reg, val);
+
+ mutex_lock(&lp->mdio_mutex);
+
+ if (xemaclite_mdio_wait(lp)) {
+ mutex_unlock(&lp->mdio_mutex);
+ return -ETIMEDOUT;
+ }
+
+ /* Write the PHY address, register number and clear the OP bit in the
+ * MDIO Address register and then write the value into the MDIO Write
+ * Data register. Finally, set the Status bit in the MDIO Control
+ * register to start a MDIO write transaction.
+ */
+ ctrl_reg = in_be32(lp->base_addr + XEL_MDIOCTRL_OFFSET);
+ out_be32(lp->base_addr + XEL_MDIOADDR_OFFSET,
+ ~XEL_MDIOADDR_OP_MASK &
+ ((phy_id << XEL_MDIOADDR_PHYADR_SHIFT) | reg));
+ out_be32(lp->base_addr + XEL_MDIOWR_OFFSET, val);
+ out_be32(lp->base_addr + XEL_MDIOCTRL_OFFSET,
+ ctrl_reg | XEL_MDIOCTRL_MDIOSTS_MASK);
+
+ mutex_unlock(&lp->mdio_mutex);
+
+ return 0;
+}
+
+/**
+ * xemaclite_mdio_reset - Reset the mdio bus.
+ * @bus: Pointer to the MII bus
+ *
+ * This function is required(?) as per Documentation/networking/phy.txt.
+ * There is no reset in this device; this function always returns 0.
+ */
+static int xemaclite_mdio_reset(struct mii_bus *bus)
+{
+ return 0;
+}
+
+/**
+ * xemaclite_mdio_setup - Register mii_bus for the Emaclite device
+ * @lp: Pointer to the Emaclite device private data
+ * @ofdev: Pointer to OF device structure
+ *
+ * This function enables MDIO bus in the Emaclite device and registers a
+ * mii_bus.
+ *
+ * Return: 0 upon success or a negative error upon failure
+ */
+static int xemaclite_mdio_setup(struct net_local *lp, struct device *dev)
+{
+ struct mii_bus *bus;
+ int rc;
+ struct resource res;
+ struct device_node *np = of_get_parent(lp->phy_node);
+
+ /* Don't register the MDIO bus if the phy_node or its parent node
+ * can't be found.
+ */
+ if (!np)
+ return -ENODEV;
+
+ /* Enable the MDIO bus by asserting the enable bit in MDIO Control
+ * register.
+ */
+ out_be32(lp->base_addr + XEL_MDIOCTRL_OFFSET,
+ XEL_MDIOCTRL_MDIOEN_MASK);
+
+ bus = mdiobus_alloc();
+ if (!bus)
+ return -ENOMEM;
+
+ of_address_to_resource(np, 0, &res);
+ snprintf(bus->id, MII_BUS_ID_SIZE, "%.8llx",
+ (unsigned long long)res.start);
+ bus->priv = lp;
+ bus->name = "Xilinx Emaclite MDIO";
+ bus->read = xemaclite_mdio_read;
+ bus->write = xemaclite_mdio_write;
+ bus->reset = xemaclite_mdio_reset;
+ bus->parent = dev;
+ bus->irq = lp->mdio_irqs; /* preallocated IRQ table */
+
+ lp->mii_bus = bus;
+
+ rc = of_mdiobus_register(bus, np);
+ if (rc)
+ goto err_register;
+
+ return 0;
+
+err_register:
+ mdiobus_free(bus);
+ return rc;
+}
+
+/**
+ * xemaclite_adjust_link - Link state callback for the Emaclite device
+ * @ndev: pointer to net_device struct
+ *
+ * There's nothing in the Emaclite device to be configured when the link
+ * state changes. We just print the status.
+ */
+void xemaclite_adjust_link(struct net_device *ndev)
+{
+ struct net_local *lp = netdev_priv(ndev);
+ struct phy_device *phy = lp->phy_dev;
+ int link_state;
+
+ /* hash together the state values to decide if something has changed */
+ link_state = phy->speed | (phy->duplex << 1) | phy->link;
+
+ if (lp->last_link != link_state) {
+ lp->last_link = link_state;
+ phy_print_status(phy);
+ }
+}
+
/**
* xemaclite_open - Open the network device
* @dev: Pointer to the network device
*
* This function sets the MAC address, requests an IRQ and enables interrupts
* for the Emaclite device and starts the Tx queue.
+ * It also connects to the phy device, if MDIO is included in Emaclite device.
*/
static int xemaclite_open(struct net_device *dev)
{
@@ -656,14 +941,50 @@ static int xemaclite_open(struct net_device *dev)
/* Just to be safe, stop the device first */
xemaclite_disable_interrupts(lp);
+ if (lp->phy_node) {
+ u32 bmcr;
+
+ lp->phy_dev = of_phy_connect(lp->ndev, lp->phy_node,
+ xemaclite_adjust_link, 0,
+ PHY_INTERFACE_MODE_MII);
+ if (!lp->phy_dev) {
+ dev_err(&lp->ndev->dev, "of_phy_connect() failed\n");
+ return -ENODEV;
+ }
+
+ /* EmacLite doesn't support giga-bit speeds */
+ lp->phy_dev->supported &= (PHY_BASIC_FEATURES);
+ lp->phy_dev->advertising = lp->phy_dev->supported;
+
+ /* Don't advertise 1000BASE-T Full/Half duplex speeds */
+ xemaclite_mdio_write(lp->mii_bus, lp->phy_dev->addr,
+ MII_CTRL1000, 0x00);
+ /* Advertise only 10 and 100mbps full/half duplex speeds */
+ xemaclite_mdio_write(lp->mii_bus, lp->phy_dev->addr,
+ MII_ADVERTISE, ADVERTISE_ALL);
+
+ /* Restart auto negotiation */
+ bmcr = xemaclite_mdio_read(lp->mii_bus,
+ lp->phy_dev->addr, MII_BMCR);
+ bmcr |= (BMCR_ANENABLE | BMCR_ANRESTART);
+ xemaclite_mdio_write(lp->mii_bus, lp->phy_dev->addr,
+ MII_BMCR, bmcr);
+
+ phy_start(lp->phy_dev);
+ }
+
/* Set the MAC address each time opened */
- xemaclite_set_mac_address(lp, dev->dev_addr);
+ xemaclite_update_address(lp, dev->dev_addr);
/* Grab the IRQ */
retval = request_irq(dev->irq, xemaclite_interrupt, 0, dev->name, dev);
if (retval) {
dev_err(&lp->ndev->dev, "Could not allocate interrupt %d\n",
dev->irq);
+ if (lp->phy_dev)
+ phy_disconnect(lp->phy_dev);
+ lp->phy_dev = NULL;
+
return retval;
}
@@ -682,6 +1003,7 @@ static int xemaclite_open(struct net_device *dev)
*
* This function stops the Tx queue, disables interrupts and frees the IRQ for
* the Emaclite device.
+ * It also disconnects the phy device associated with the Emaclite device.
*/
static int xemaclite_close(struct net_device *dev)
{
@@ -691,6 +1013,10 @@ static int xemaclite_close(struct net_device *dev)
xemaclite_disable_interrupts(lp);
free_irq(dev->irq, dev);
+ if (lp->phy_dev)
+ phy_disconnect(lp->phy_dev);
+ lp->phy_dev = NULL;
+
return 0;
}
@@ -754,42 +1080,6 @@ static int xemaclite_send(struct sk_buff *orig_skb, struct net_device *dev)
}
/**
- * xemaclite_ioctl - Perform IO Control operations on the network device
- * @dev: Pointer to the network device
- * @rq: Pointer to the interface request structure
- * @cmd: IOCTL command
- *
- * The only IOCTL operation supported by this function is setting the MAC
- * address. An error is reported if any other operations are requested.
- *
- * Return: 0 to indicate success, or a negative error for failure.
- */
-static int xemaclite_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
-{
- struct net_local *lp = (struct net_local *) netdev_priv(dev);
- struct hw_addr_data *hw_addr = (struct hw_addr_data *) &rq->ifr_hwaddr;
-
- switch (cmd) {
- case SIOCETHTOOL:
- return -EIO;
-
- case SIOCSIFHWADDR:
- dev_err(&lp->ndev->dev, "SIOCSIFHWADDR\n");
-
- /* Copy MAC address in from user space */
- copy_from_user((void __force *) dev->dev_addr,
- (void __user __force *) hw_addr,
- IFHWADDRLEN);
- xemaclite_set_mac_address(lp, dev->dev_addr);
- break;
- default:
- return -EOPNOTSUPP;
- }
-
- return 0;
-}
-
-/**
* xemaclite_remove_ndev - Free the network device
* @ndev: Pointer to the network device to be freed
*
@@ -840,6 +1130,8 @@ static struct net_device_ops xemaclite_netdev_ops;
* This function probes for the Emaclite device in the device tree.
* It initializes the driver data structure and the hardware, sets the MAC
* address and registers the network device.
+ * It also registers a mii_bus for the Emaclite device, if MDIO is included
+ * in the device.
*
* Return: 0, if the driver is bound to the Emaclite device, or
* a negative error if there is failure.
@@ -880,6 +1172,7 @@ static int __devinit xemaclite_of_probe(struct of_device *ofdev,
}
dev_set_drvdata(dev, ndev);
+ SET_NETDEV_DEV(ndev, &ofdev->dev);
ndev->irq = r_irq.start;
ndev->mem_start = r_mem.start;
@@ -906,6 +1199,7 @@ static int __devinit xemaclite_of_probe(struct of_device *ofdev,
}
spin_lock_init(&lp->reset_lock);
+ mutex_init(&lp->mdio_mutex);
lp->next_tx_buf_to_use = 0x0;
lp->next_rx_buf_to_use = 0x0;
lp->tx_ping_pong = get_bool(ofdev, "xlnx,tx-ping-pong");
@@ -923,7 +1217,12 @@ static int __devinit xemaclite_of_probe(struct of_device *ofdev,
out_be32(lp->base_addr + XEL_BUFFER_OFFSET + XEL_TSR_OFFSET, 0);
/* Set the MAC address in the EmacLite device */
- xemaclite_set_mac_address(lp, ndev->dev_addr);
+ xemaclite_update_address(lp, ndev->dev_addr);
+
+ lp->phy_node = of_parse_phandle(ofdev->node, "phy-handle", 0);
+ rc = xemaclite_mdio_setup(lp, &ofdev->dev);
+ if (rc)
+ dev_warn(&ofdev->dev, "error registering MDIO bus\n");
dev_info(dev,
"MAC address is now %2x:%2x:%2x:%2x:%2x:%2x\n",
@@ -972,12 +1271,25 @@ static int __devexit xemaclite_of_remove(struct of_device *of_dev)
struct device *dev = &of_dev->dev;
struct net_device *ndev = dev_get_drvdata(dev);
+ struct net_local *lp = (struct net_local *) netdev_priv(ndev);
+
+ /* Un-register the mii_bus, if configured */
+ if (lp->has_mdio) {
+ mdiobus_unregister(lp->mii_bus);
+ kfree(lp->mii_bus->irq);
+ mdiobus_free(lp->mii_bus);
+ lp->mii_bus = NULL;
+ }
+
unregister_netdev(ndev);
+ if (lp->phy_node)
+ of_node_put(lp->phy_node);
+ lp->phy_node = NULL;
+
release_mem_region(ndev->mem_start, ndev->mem_end-ndev->mem_start + 1);
xemaclite_remove_ndev(ndev);
-
dev_set_drvdata(dev, NULL);
return 0;
@@ -987,7 +1299,7 @@ static struct net_device_ops xemaclite_netdev_ops = {
.ndo_open = xemaclite_open,
.ndo_stop = xemaclite_close,
.ndo_start_xmit = xemaclite_send,
- .ndo_do_ioctl = xemaclite_ioctl,
+ .ndo_set_mac_address = xemaclite_set_mac_address,
.ndo_tx_timeout = xemaclite_tx_timeout,
.ndo_get_stats = xemaclite_get_stats,
};
@@ -999,6 +1311,7 @@ static struct of_device_id xemaclite_of_match[] __devinitdata = {
{ .compatible = "xlnx,xps-ethernetlite-1.00.a", },
{ .compatible = "xlnx,xps-ethernetlite-2.00.a", },
{ .compatible = "xlnx,xps-ethernetlite-2.01.a", },
+ { .compatible = "xlnx,xps-ethernetlite-3.00.a", },
{ /* end of list */ },
};
MODULE_DEVICE_TABLE(of, xemaclite_of_match);
--
1.6.2.1
This email and any attachments are intended for the sole use of the named recipient(s) and contain(s) confidential information that may be proprietary, privileged or copyrighted under applicable law. If you are not the intended recipient, do not read, copy, or forward this email message or any attachments. Delete this email message and any attachments immediately.
^ permalink raw reply related
* [PATCH v2 0/3] powerpc: mpc5121: PSC UART support
From: Anatolij Gustschin @ 2010-02-09 21:13 UTC (permalink / raw)
To: linuxppc-dev; +Cc: wd, dzu, gregkh, linux-kernel, Anatolij Gustschin
The support for mpc5121 PSC UART currently only works with
serial console. This patch series re-enable PSC UART support for
all 12 PSCs and document added DTS bingings.
Anatolij Gustschin (3):
serial: mpc52xx_uart: re-enable mpc5121 PSC UART support
powerpc: doc/dts-bindings: document mpc5121 psc uart dts-bindings
powerpc: mpc5121: enable support for more PSC UARTs
.../powerpc/dts-bindings/fsl/mpc5121-psc.txt | 70 ++++++
arch/powerpc/include/asm/mpc52xx_psc.h | 4 +
drivers/serial/mpc52xx_uart.c | 251 ++++++++++++++++++--
3 files changed, 310 insertions(+), 15 deletions(-)
create mode 100644 Documentation/powerpc/dts-bindings/fsl/mpc5121-psc.txt
^ permalink raw reply
* [PATCH v2 1/3] serial: mpc52xx_uart: re-enable mpc5121 PSC UART support
From: Anatolij Gustschin @ 2010-02-09 21:13 UTC (permalink / raw)
To: linuxppc-dev; +Cc: wd, dzu, gregkh, linux-kernel, Anatolij Gustschin
In-Reply-To: <1265750032-2803-1-git-send-email-agust@denx.de>
Currently the support for MPC5121 PSC UART in the mpc52xx_uart
driver is broken (only console pre-initialized by the bootloader
works). Re-enable it now by providing MPC5121 specific ops
for PSCx clock activation, FIFO controller init/uninit and
MPC5121 PSC FIFO shared interrupt handling functions.
Signed-off-by: John Rigby <jcrigby@gmail.com>
Signed-off-by: Anatolij Gustschin <agust@denx.de>
Acked-by: Grant Likely <grant.likely@secretlab.ca>
---
Changes since v1:
- droped irq_dispose_mapping() entirely as suggested by Grant.
- added John's SoB as fifoc init code is based on his code. I
forgot to add the SoB in previous patch version, sorry.
drivers/serial/mpc52xx_uart.c | 251 ++++++++++++++++++++++++++++++++++++++---
1 files changed, 236 insertions(+), 15 deletions(-)
diff --git a/drivers/serial/mpc52xx_uart.c b/drivers/serial/mpc52xx_uart.c
index 7ce9e9f..3119fdd 100644
--- a/drivers/serial/mpc52xx_uart.c
+++ b/drivers/serial/mpc52xx_uart.c
@@ -74,6 +74,7 @@
#include <linux/io.h>
#include <linux/of.h>
#include <linux/of_platform.h>
+#include <linux/clk.h>
#include <asm/mpc52xx.h>
#include <asm/mpc52xx_psc.h>
@@ -113,6 +114,7 @@ static void mpc52xx_uart_of_enumerate(void);
/* Forward declaration of the interruption handling routine */
static irqreturn_t mpc52xx_uart_int(int irq, void *dev_id);
+static irqreturn_t mpc5xxx_uart_process_int(struct uart_port *port);
/* Simple macro to test if a port is console or not. This one is taken
@@ -145,6 +147,11 @@ struct psc_ops {
void (*cw_disable_ints)(struct uart_port *port);
void (*cw_restore_ints)(struct uart_port *port);
unsigned long (*getuartclk)(void *p);
+ int (*clock)(struct uart_port *port, int enable);
+ int (*fifoc_init)(void);
+ void (*fifoc_uninit)(void);
+ void (*get_irq)(struct uart_port *, struct device_node *);
+ irqreturn_t (*handle_irq)(struct uart_port *port);
};
#ifdef CONFIG_PPC_MPC52xx
@@ -256,6 +263,18 @@ static unsigned long mpc52xx_getuartclk(void *p)
return mpc5xxx_get_bus_frequency(p) / 2;
}
+static void mpc52xx_psc_get_irq(struct uart_port *port, struct device_node *np)
+{
+ port->irqflags = IRQF_DISABLED;
+ port->irq = irq_of_parse_and_map(np, 0);
+}
+
+/* 52xx specific interrupt handler. The caller holds the port lock */
+static irqreturn_t mpc52xx_psc_handle_irq(struct uart_port *port)
+{
+ return mpc5xxx_uart_process_int(port);
+}
+
static struct psc_ops mpc52xx_psc_ops = {
.fifo_init = mpc52xx_psc_fifo_init,
.raw_rx_rdy = mpc52xx_psc_raw_rx_rdy,
@@ -273,14 +292,32 @@ static struct psc_ops mpc52xx_psc_ops = {
.cw_disable_ints = mpc52xx_psc_cw_disable_ints,
.cw_restore_ints = mpc52xx_psc_cw_restore_ints,
.getuartclk = mpc52xx_getuartclk,
+ .get_irq = mpc52xx_psc_get_irq,
+ .handle_irq = mpc52xx_psc_handle_irq,
};
#endif /* CONFIG_MPC52xx */
#ifdef CONFIG_PPC_MPC512x
#define FIFO_512x(port) ((struct mpc512x_psc_fifo __iomem *)(PSC(port)+1))
+
+/* PSC FIFO Controller for mpc512x */
+struct psc_fifoc {
+ u32 fifoc_cmd;
+ u32 fifoc_int;
+ u32 fifoc_dma;
+ u32 fifoc_axe;
+ u32 fifoc_debug;
+};
+
+static struct psc_fifoc __iomem *psc_fifoc;
+static unsigned int psc_fifoc_irq;
+
static void mpc512x_psc_fifo_init(struct uart_port *port)
{
+ /* /32 prescaler */
+ out_be16(&PSC(port)->mpc52xx_psc_clock_select, 0xdd00);
+
out_be32(&FIFO_512x(port)->txcmd, MPC512x_PSC_FIFO_RESET_SLICE);
out_be32(&FIFO_512x(port)->txcmd, MPC512x_PSC_FIFO_ENABLE_SLICE);
out_be32(&FIFO_512x(port)->txalarm, 1);
@@ -393,6 +430,160 @@ static unsigned long mpc512x_getuartclk(void *p)
return mpc5xxx_get_bus_frequency(p);
}
+#define DEFAULT_FIFO_SIZE 16
+
+static unsigned int __init get_fifo_size(struct device_node *np,
+ char *fifo_name)
+{
+ const unsigned int *fp;
+
+ fp = of_get_property(np, fifo_name, NULL);
+ if (fp)
+ return *fp;
+
+ pr_warning("no %s property in %s node, defaulting to %d\n",
+ fifo_name, np->full_name, DEFAULT_FIFO_SIZE);
+
+ return DEFAULT_FIFO_SIZE;
+}
+
+#define FIFOC(_base) ((struct mpc512x_psc_fifo __iomem *) \
+ ((u32)(_base) + sizeof(struct mpc52xx_psc)))
+
+/* Init PSC FIFO Controller */
+static int __init mpc512x_psc_fifoc_init(void)
+{
+ struct device_node *np;
+ void __iomem *psc;
+ unsigned int tx_fifo_size;
+ unsigned int rx_fifo_size;
+ int fifobase = 0; /* current fifo address in 32 bit words */
+
+ np = of_find_compatible_node(NULL, NULL,
+ "fsl,mpc5121-psc-fifo");
+ if (!np) {
+ pr_err("%s: Can't find FIFOC node\n", __func__);
+ return -ENODEV;
+ }
+
+ psc_fifoc = of_iomap(np, 0);
+ if (!psc_fifoc) {
+ pr_err("%s: Can't map FIFOC\n", __func__);
+ return -ENODEV;
+ }
+
+ psc_fifoc_irq = irq_of_parse_and_map(np, 0);
+ of_node_put(np);
+ if (psc_fifoc_irq == NO_IRQ) {
+ pr_err("%s: Can't get FIFOC irq\n", __func__);
+ iounmap(psc_fifoc);
+ return -ENODEV;
+ }
+
+ for_each_compatible_node(np, NULL, "fsl,mpc5121-psc-uart") {
+ tx_fifo_size = get_fifo_size(np, "fsl,tx-fifo-size");
+ rx_fifo_size = get_fifo_size(np, "fsl,rx-fifo-size");
+
+ /* size in register is in 4 byte units */
+ tx_fifo_size /= 4;
+ rx_fifo_size /= 4;
+ if (!tx_fifo_size)
+ tx_fifo_size = 1;
+ if (!rx_fifo_size)
+ rx_fifo_size = 1;
+
+ psc = of_iomap(np, 0);
+ if (!psc) {
+ pr_err("%s: Can't map %s device\n",
+ __func__, np->full_name);
+ continue;
+ }
+
+ /* FIFO space is 4KiB, check if requested size is available */
+ if ((fifobase + tx_fifo_size + rx_fifo_size) > 0x1000) {
+ pr_err("%s: no fifo space available for %s\n",
+ __func__, np->full_name);
+ iounmap(psc);
+ /*
+ * chances are that another device requests less
+ * fifo space, so we continue.
+ */
+ continue;
+ }
+ /* set tx and rx fifo size registers */
+ out_be32(&FIFOC(psc)->txsz, (fifobase << 16) | tx_fifo_size);
+ fifobase += tx_fifo_size;
+ out_be32(&FIFOC(psc)->rxsz, (fifobase << 16) | rx_fifo_size);
+ fifobase += rx_fifo_size;
+
+ /* reset and enable the slices */
+ out_be32(&FIFOC(psc)->txcmd, 0x80);
+ out_be32(&FIFOC(psc)->txcmd, 0x01);
+ out_be32(&FIFOC(psc)->rxcmd, 0x80);
+ out_be32(&FIFOC(psc)->rxcmd, 0x01);
+
+ iounmap(psc);
+ }
+
+ return 0;
+}
+
+static void __exit mpc512x_psc_fifoc_uninit(void)
+{
+ iounmap(psc_fifoc);
+}
+
+/* 512x specific interrupt handler. The caller holds the port lock */
+static irqreturn_t mpc512x_psc_handle_irq(struct uart_port *port)
+{
+ unsigned long fifoc_int;
+ int psc_num;
+
+ /* Read pending PSC FIFOC interrupts */
+ fifoc_int = in_be32(&psc_fifoc->fifoc_int);
+
+ /* Check if it is an interrupt for this port */
+ psc_num = (port->mapbase & 0xf00) >> 8;
+ if (test_bit(psc_num, &fifoc_int) ||
+ test_bit(psc_num + 16, &fifoc_int))
+ return mpc5xxx_uart_process_int(port);
+
+ return IRQ_NONE;
+}
+
+static int mpc512x_psc_clock(struct uart_port *port, int enable)
+{
+ struct clk *psc_clk;
+ int psc_num;
+ char clk_name[10];
+
+ if (uart_console(port))
+ return 0;
+
+ psc_num = (port->mapbase & 0xf00) >> 8;
+ snprintf(clk_name, sizeof(clk_name), "psc%d_clk", psc_num);
+ psc_clk = clk_get(port->dev, clk_name);
+ if (IS_ERR(psc_clk)) {
+ dev_err(port->dev, "Failed to get PSC clock entry!\n");
+ return -ENODEV;
+ }
+
+ dev_dbg(port->dev, "%s %sable\n", clk_name, enable ? "en" : "dis");
+
+ if (enable)
+ clk_enable(psc_clk);
+ else
+ clk_disable(psc_clk);
+
+ return 0;
+}
+
+static void mpc512x_psc_get_irq(struct uart_port *port, struct device_node *np)
+{
+ port->irqflags = IRQF_SHARED;
+ port->irq = psc_fifoc_irq;
+}
+
static struct psc_ops mpc512x_psc_ops = {
.fifo_init = mpc512x_psc_fifo_init,
.raw_rx_rdy = mpc512x_psc_raw_rx_rdy,
@@ -410,6 +601,11 @@ static struct psc_ops mpc512x_psc_ops = {
.cw_disable_ints = mpc512x_psc_cw_disable_ints,
.cw_restore_ints = mpc512x_psc_cw_restore_ints,
.getuartclk = mpc512x_getuartclk,
+ .clock = mpc512x_psc_clock,
+ .fifoc_init = mpc512x_psc_fifoc_init,
+ .fifoc_uninit = mpc512x_psc_fifoc_uninit,
+ .get_irq = mpc512x_psc_get_irq,
+ .handle_irq = mpc512x_psc_handle_irq,
};
#endif
@@ -519,10 +715,15 @@ mpc52xx_uart_startup(struct uart_port *port)
struct mpc52xx_psc __iomem *psc = PSC(port);
int ret;
+ if (psc_ops->clock) {
+ ret = psc_ops->clock(port, 1);
+ if (ret)
+ return ret;
+ }
+
/* Request IRQ */
ret = request_irq(port->irq, mpc52xx_uart_int,
- IRQF_DISABLED | IRQF_SAMPLE_RANDOM,
- "mpc52xx_psc_uart", port);
+ port->irqflags, "mpc52xx_psc_uart", port);
if (ret)
return ret;
@@ -553,6 +754,9 @@ mpc52xx_uart_shutdown(struct uart_port *port)
port->read_status_mask = 0;
out_be16(&psc->mpc52xx_psc_imr, port->read_status_mask);
+ if (psc_ops->clock)
+ psc_ops->clock(port, 0);
+
/* Release interrupt */
free_irq(port->irq, port);
}
@@ -851,15 +1055,12 @@ mpc52xx_uart_int_tx_chars(struct uart_port *port)
}
static irqreturn_t
-mpc52xx_uart_int(int irq, void *dev_id)
+mpc5xxx_uart_process_int(struct uart_port *port)
{
- struct uart_port *port = dev_id;
unsigned long pass = ISR_PASS_LIMIT;
unsigned int keepgoing;
u8 status;
- spin_lock(&port->lock);
-
/* While we have stuff to do, we continue */
do {
/* If we don't find anything to do, we stop */
@@ -886,11 +1087,23 @@ mpc52xx_uart_int(int irq, void *dev_id)
} while (keepgoing);
- spin_unlock(&port->lock);
-
return IRQ_HANDLED;
}
+static irqreturn_t
+mpc52xx_uart_int(int irq, void *dev_id)
+{
+ struct uart_port *port = dev_id;
+ irqreturn_t ret;
+
+ spin_lock(&port->lock);
+
+ ret = psc_ops->handle_irq(port);
+
+ spin_unlock(&port->lock);
+
+ return ret;
+}
/* ======================================================================== */
/* Console ( if applicable ) */
@@ -1152,7 +1365,7 @@ mpc52xx_uart_of_probe(struct of_device *op, const struct of_device_id *match)
return -EINVAL;
}
- port->irq = irq_of_parse_and_map(op->node, 0);
+ psc_ops->get_irq(port, op->node);
if (port->irq == NO_IRQ) {
dev_dbg(&op->dev, "Could not get irq\n");
return -EINVAL;
@@ -1163,10 +1376,8 @@ mpc52xx_uart_of_probe(struct of_device *op, const struct of_device_id *match)
/* Add the port to the uart sub-system */
ret = uart_add_one_port(&mpc52xx_uart_driver, port);
- if (ret) {
- irq_dispose_mapping(port->irq);
+ if (ret)
return ret;
- }
dev_set_drvdata(&op->dev, (void *)port);
return 0;
@@ -1178,10 +1389,8 @@ mpc52xx_uart_of_remove(struct of_device *op)
struct uart_port *port = dev_get_drvdata(&op->dev);
dev_set_drvdata(&op->dev, NULL);
- if (port) {
+ if (port)
uart_remove_one_port(&mpc52xx_uart_driver, port);
- irq_dispose_mapping(port->irq);
- }
return 0;
}
@@ -1288,6 +1497,15 @@ mpc52xx_uart_init(void)
mpc52xx_uart_of_enumerate();
+ /*
+ * Map the PSC FIFO Controller and init if on MPC512x.
+ */
+ if (psc_ops->fifoc_init) {
+ ret = psc_ops->fifoc_init();
+ if (ret)
+ return ret;
+ }
+
ret = of_register_platform_driver(&mpc52xx_uart_of_driver);
if (ret) {
printk(KERN_ERR "%s: of_register_platform_driver failed (%i)\n",
@@ -1302,6 +1520,9 @@ mpc52xx_uart_init(void)
static void __exit
mpc52xx_uart_exit(void)
{
+ if (psc_ops->fifoc_uninit)
+ psc_ops->fifoc_uninit();
+
of_unregister_platform_driver(&mpc52xx_uart_of_driver);
uart_unregister_driver(&mpc52xx_uart_driver);
}
--
1.6.3.3
^ permalink raw reply related
* [PATCH v2 2/3] powerpc: doc/dts-bindings: document mpc5121 psc uart dts-bindings
From: Anatolij Gustschin @ 2010-02-09 21:13 UTC (permalink / raw)
To: linuxppc-dev; +Cc: wd, dzu, gregkh, linux-kernel, Anatolij Gustschin
In-Reply-To: <1265750032-2803-1-git-send-email-agust@denx.de>
Support for MPC5121 PSC UART in the mpc52xx_uart driver
added new DTS properties for FSL MPC5121 PSC FIFO Controller.
Provide documentation of the new properties and some examples.
Signed-off-by: Anatolij Gustschin <agust@denx.de>
Acked-by: Grant Likely <grant.likely@secretlab.ca>
---
No changes since v1.
.../powerpc/dts-bindings/fsl/mpc5121-psc.txt | 70 ++++++++++++++++++++
1 files changed, 70 insertions(+), 0 deletions(-)
create mode 100644 Documentation/powerpc/dts-bindings/fsl/mpc5121-psc.txt
diff --git a/Documentation/powerpc/dts-bindings/fsl/mpc5121-psc.txt b/Documentation/powerpc/dts-bindings/fsl/mpc5121-psc.txt
new file mode 100644
index 0000000..8832e87
--- /dev/null
+++ b/Documentation/powerpc/dts-bindings/fsl/mpc5121-psc.txt
@@ -0,0 +1,70 @@
+MPC5121 PSC Device Tree Bindings
+
+PSC in UART mode
+----------------
+
+For PSC in UART mode the needed PSC serial devices
+are specified by fsl,mpc5121-psc-uart nodes in the
+fsl,mpc5121-immr SoC node. Additionally the PSC FIFO
+Controller node fsl,mpc5121-psc-fifo is requered there:
+
+fsl,mpc5121-psc-uart nodes
+--------------------------
+
+Required properties :
+ - compatible : Should contain "fsl,mpc5121-psc-uart" and "fsl,mpc5121-psc"
+ - cell-index : Index of the PSC in hardware
+ - reg : Offset and length of the register set for the PSC device
+ - interrupts : <a b> where a is the interrupt number of the
+ PSC FIFO Controller and b is a field that represents an
+ encoding of the sense and level information for the interrupt.
+ - interrupt-parent : the phandle for the interrupt controller that
+ services interrupts for this device.
+
+Recommended properties :
+ - fsl,rx-fifo-size : the size of the RX fifo slice (a multiple of 4)
+ - fsl,tx-fifo-size : the size of the TX fifo slice (a multiple of 4)
+
+
+fsl,mpc5121-psc-fifo node
+-------------------------
+
+Required properties :
+ - compatible : Should be "fsl,mpc5121-psc-fifo"
+ - reg : Offset and length of the register set for the PSC
+ FIFO Controller
+ - interrupts : <a b> where a is the interrupt number of the
+ PSC FIFO Controller and b is a field that represents an
+ encoding of the sense and level information for the interrupt.
+ - interrupt-parent : the phandle for the interrupt controller that
+ services interrupts for this device.
+
+
+Example for a board using PSC0 and PSC1 devices in serial mode:
+
+serial@11000 {
+ compatible = "fsl,mpc5121-psc-uart", "fsl,mpc5121-psc";
+ cell-index = <0>;
+ reg = <0x11000 0x100>;
+ interrupts = <40 0x8>;
+ interrupt-parent = < &ipic >;
+ fsl,rx-fifo-size = <16>;
+ fsl,tx-fifo-size = <16>;
+};
+
+serial@11100 {
+ compatible = "fsl,mpc5121-psc-uart", "fsl,mpc5121-psc";
+ cell-index = <1>;
+ reg = <0x11100 0x100>;
+ interrupts = <40 0x8>;
+ interrupt-parent = < &ipic >;
+ fsl,rx-fifo-size = <16>;
+ fsl,tx-fifo-size = <16>;
+};
+
+pscfifo@11f00 {
+ compatible = "fsl,mpc5121-psc-fifo";
+ reg = <0x11f00 0x100>;
+ interrupts = <40 0x8>;
+ interrupt-parent = < &ipic >;
+};
--
1.6.3.3
^ permalink raw reply related
* [PATCH v2 3/3] powerpc: mpc5121: enable support for more PSC UARTs
From: Anatolij Gustschin @ 2010-02-09 21:13 UTC (permalink / raw)
To: linuxppc-dev; +Cc: wd, dzu, gregkh, linux-kernel, Anatolij Gustschin
In-Reply-To: <1265750032-2803-1-git-send-email-agust@denx.de>
MPC5121 has 12 PSC devices. Enable UART support for all of
them by defining the number of max. PSCs depending on
selection of PPC_MPC512x platform support.
Signed-off-by: Anatolij Gustschin <agust@denx.de>
Acked-by: Grant Likely <grant.likely@secretlab.ca>
---
No changes since v1.
arch/powerpc/include/asm/mpc52xx_psc.h | 4 ++++
1 files changed, 4 insertions(+), 0 deletions(-)
diff --git a/arch/powerpc/include/asm/mpc52xx_psc.h b/arch/powerpc/include/asm/mpc52xx_psc.h
index fb84120..42561f4 100644
--- a/arch/powerpc/include/asm/mpc52xx_psc.h
+++ b/arch/powerpc/include/asm/mpc52xx_psc.h
@@ -25,7 +25,11 @@
#include <asm/types.h>
/* Max number of PSCs */
+#ifdef CONFIG_PPC_MPC512x
+#define MPC52xx_PSC_MAXNUM 12
+#else
#define MPC52xx_PSC_MAXNUM 6
+#endif
/* Programmable Serial Controller (PSC) status register bits */
#define MPC52xx_PSC_SR_UNEX_RX 0x0001
--
1.6.3.3
^ permalink raw reply related
* Re: [PATCH] Restrict initial stack space expansion to rlimit
From: Andrew Morton @ 2010-02-09 21:25 UTC (permalink / raw)
To: Michael Neuling
Cc: linux-parisc, linux-kernel, aeb, Oleg Nesterov, miltonm,
James Morris, linuxppc-dev, Paul Mackerras, Anton Blanchard,
KOSAKI Motohiro, Serge Hallyn, linux-fsdevel, Americo Wang,
Ingo Molnar, Linus Torvalds, stable, Alexander Viro
In-Reply-To: <11046.1265705967@neuling.org>
On Tue, 09 Feb 2010 19:59:27 +1100
Michael Neuling <mikey@neuling.org> wrote:
> > > + /* Initial stack must not cause stack overflow. */
> > > + if (stack_expand > stack_expand_lim)
> > > + stack_expand = stack_expand_lim;
> > > #ifdef CONFIG_STACK_GROWSUP
> > > - stack_base = vma->vm_end + EXTRA_STACK_VM_PAGES * PAGE_SIZE;
> > > + stack_base = vma->vm_end + stack_expand;
> > > #else
> > > - stack_base = vma->vm_start - EXTRA_STACK_VM_PAGES * PAGE_SIZE;
> > > + stack_base = vma->vm_start - stack_expand;
> > > #endif
> > > ret = expand_stack(vma, stack_base);
> > > if (ret)
> >
> > Umm.. It looks correct. but the nested complex if statement seems a bit ugly.
> > Instead, How about following?
>
> I don't like the duplicated code in the #ifdef/else but I can live with it.
cleanup the cleanup:
--- a/fs/exec.c~fs-execc-restrict-initial-stack-space-expansion-to-rlimit-cleanup-cleanup
+++ a/fs/exec.c
@@ -637,20 +637,17 @@ int setup_arg_pages(struct linux_binprm
* will align it up.
*/
rlim_stack = rlimit(RLIMIT_STACK) & PAGE_MASK;
- if (rlim_stack < stack_size)
- rlim_stack = stack_size;
+ rlim_stack = min(rlim_stack, stack_size);
#ifdef CONFIG_STACK_GROWSUP
- if (stack_size + stack_expand > rlim_stack) {
+ if (stack_size + stack_expand > rlim_stack)
stack_base = vma->vm_start + rlim_stack;
- } else {
+ else
stack_base = vma->vm_end + stack_expand;
- }
#else
- if (stack_size + stack_expand > rlim_stack) {
+ if (stack_size + stack_expand > rlim_stack)
stack_base = vma->vm_end - rlim_stack;
- } else {
+ else
stack_base = vma->vm_start - stack_expand;
- }
#endif
ret = expand_stack(vma, stack_base);
if (ret)
_
> > note: it's untested.
>
> Works for me on ppc64 with 4k and 64k pages. Thanks!
>
> I'd still like someone with a CONFIG_STACK_GROWSUP arch to test/ACK it
> as well.
There's only one CONFIG_GROWSUP arch - parisc.
Guys, here's the rolled-up patch. Could someone please test it on
parisc?
err, I'm not sure what one needs to do to test it, actually.
Presumably it involves setting an unusual `ulimit -s'. Can someone
please suggest a test plan?
From: Michael Neuling <mikey@neuling.org>
When reserving stack space for a new process, make sure we're not
attempting to expand the stack by more than rlimit allows.
This fixes a bug caused by b6a2fea39318e43fee84fa7b0b90d68bed92d2ba ("mm:
variable length argument support") and unmasked by
fc63cf237078c86214abcb2ee9926d8ad289da9b ("exec: setup_arg_pages() fails
to return errors").
This bug means that when limiting the stack to less the 20*PAGE_SIZE (eg.
80K on 4K pages or 'ulimit -s 79') all processes will be killed before
they start. This is particularly bad with 64K pages, where a ulimit below
1280K will kill every process.
Signed-off-by: Michael Neuling <mikey@neuling.org>
Cc: KOSAKI Motohiro <kosaki.motohiro@jp.fujitsu.com>
Cc: Americo Wang <xiyou.wangcong@gmail.com>
Cc: Anton Blanchard <anton@samba.org>
Cc: Oleg Nesterov <oleg@redhat.com>
Cc: James Morris <jmorris@namei.org>
Cc: Ingo Molnar <mingo@elte.hu>
Cc: Serge Hallyn <serue@us.ibm.com>
Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Cc: <stable@kernel.org>
fs/exec.c | 21 +++++++++++++++++++--
1 file changed, 19 insertions(+), 2 deletions(-)
diff -puN fs/exec.c~fs-execc-restrict-initial-stack-space-expansion-to-rlimit fs/exec.c
--- a/fs/exec.c~fs-execc-restrict-initial-stack-space-expansion-to-rlimit
+++ a/fs/exec.c
@@ -571,6 +571,9 @@ int setup_arg_pages(struct linux_binprm
struct vm_area_struct *prev = NULL;
unsigned long vm_flags;
unsigned long stack_base;
+ unsigned long stack_size;
+ unsigned long stack_expand;
+ unsigned long rlim_stack;
#ifdef CONFIG_STACK_GROWSUP
/* Limit stack size to 1GB */
@@ -627,10 +630,24 @@ int setup_arg_pages(struct linux_binprm
goto out_unlock;
}
+ stack_expand = EXTRA_STACK_VM_PAGES * PAGE_SIZE;
+ stack_size = vma->vm_end - vma->vm_start;
+ /*
+ * Align this down to a page boundary as expand_stack
+ * will align it up.
+ */
+ rlim_stack = rlimit(RLIMIT_STACK) & PAGE_MASK;
+ rlim_stack = min(rlim_stack, stack_size);
#ifdef CONFIG_STACK_GROWSUP
- stack_base = vma->vm_end + EXTRA_STACK_VM_PAGES * PAGE_SIZE;
+ if (stack_size + stack_expand > rlim_stack)
+ stack_base = vma->vm_start + rlim_stack;
+ else
+ stack_base = vma->vm_end + stack_expand;
#else
- stack_base = vma->vm_start - EXTRA_STACK_VM_PAGES * PAGE_SIZE;
+ if (stack_size + stack_expand > rlim_stack)
+ stack_base = vma->vm_end - rlim_stack;
+ else
+ stack_base = vma->vm_start - stack_expand;
#endif
ret = expand_stack(vma, stack_base);
if (ret)
_
^ permalink raw reply
* Re: [PATCH] Restrict initial stack space expansion to rlimit
From: Michael Neuling @ 2010-02-09 21:51 UTC (permalink / raw)
To: Andrew Morton
Cc: linux-parisc, linux-kernel, aeb, Oleg Nesterov, miltonm,
James Morris, linuxppc-dev, Paul Mackerras, Anton Blanchard,
KOSAKI Motohiro, Serge Hallyn, linux-fsdevel, Americo Wang,
Ingo Molnar, Linus Torvalds, stable, Alexander Viro
In-Reply-To: <20100209132529.bfc455b7.akpm@linux-foundation.org>
> > > note: it's untested.
> >
> > Works for me on ppc64 with 4k and 64k pages. Thanks!
> >
> > I'd still like someone with a CONFIG_STACK_GROWSUP arch to test/ACK it
> > as well.
>
> There's only one CONFIG_GROWSUP arch - parisc.
>
> Guys, here's the rolled-up patch.
FYI the rolled up patch still works fine on PPC64. Thanks.
> Could someone please test it on parisc?
>
> err, I'm not sure what one needs to do to test it, actually.
> Presumably it involves setting an unusual `ulimit -s'. Can someone
> please suggest a test plan?
How about doing:
'ulimit -s 15; ls'
before and after the patch is applied. Before it's applied, 'ls' should
be killed. After the patch is applied, 'ls' should no longer be killed.
I'm suggesting a stack limit of 15KB since it's small enough to trigger
20*PAGE_SIZE. Also 15KB not a multiple of PAGE_SIZE, which is a trickier
case to handle correctly with this code.
4K pages on parisc should be fine to test with.
Mikey
>
> From: Michael Neuling <mikey@neuling.org>
>
> When reserving stack space for a new process, make sure we're not
> attempting to expand the stack by more than rlimit allows.
>
> This fixes a bug caused by b6a2fea39318e43fee84fa7b0b90d68bed92d2ba ("mm:
> variable length argument support") and unmasked by
> fc63cf237078c86214abcb2ee9926d8ad289da9b ("exec: setup_arg_pages() fails
> to return errors").
>
> This bug means that when limiting the stack to less the 20*PAGE_SIZE (eg.
> 80K on 4K pages or 'ulimit -s 79') all processes will be killed before
> they start. This is particularly bad with 64K pages, where a ulimit below
> 1280K will kill every process.
>
> Signed-off-by: Michael Neuling <mikey@neuling.org>
> Cc: KOSAKI Motohiro <kosaki.motohiro@jp.fujitsu.com>
> Cc: Americo Wang <xiyou.wangcong@gmail.com>
> Cc: Anton Blanchard <anton@samba.org>
> Cc: Oleg Nesterov <oleg@redhat.com>
> Cc: James Morris <jmorris@namei.org>
> Cc: Ingo Molnar <mingo@elte.hu>
> Cc: Serge Hallyn <serue@us.ibm.com>
> Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
> Cc: <stable@kernel.org>
>
> fs/exec.c | 21 +++++++++++++++++++--
> 1 file changed, 19 insertions(+), 2 deletions(-)
>
> diff -puN fs/exec.c~fs-execc-restrict-initial-stack-space-expansion-to-rlimit
fs/exec.c
> --- a/fs/exec.c~fs-execc-restrict-initial-stack-space-expansion-to-rlimit
> +++ a/fs/exec.c
> @@ -571,6 +571,9 @@ int setup_arg_pages(struct linux_binprm
> struct vm_area_struct *prev = NULL;
> unsigned long vm_flags;
> unsigned long stack_base;
> + unsigned long stack_size;
> + unsigned long stack_expand;
> + unsigned long rlim_stack;
>
> #ifdef CONFIG_STACK_GROWSUP
> /* Limit stack size to 1GB */
> @@ -627,10 +630,24 @@ int setup_arg_pages(struct linux_binprm
> goto out_unlock;
> }
>
> + stack_expand = EXTRA_STACK_VM_PAGES * PAGE_SIZE;
> + stack_size = vma->vm_end - vma->vm_start;
> + /*
> + * Align this down to a page boundary as expand_stack
> + * will align it up.
> + */
> + rlim_stack = rlimit(RLIMIT_STACK) & PAGE_MASK;
> + rlim_stack = min(rlim_stack, stack_size);
> #ifdef CONFIG_STACK_GROWSUP
> - stack_base = vma->vm_end + EXTRA_STACK_VM_PAGES * PAGE_SIZE;
> + if (stack_size + stack_expand > rlim_stack)
> + stack_base = vma->vm_start + rlim_stack;
> + else
> + stack_base = vma->vm_end + stack_expand;
> #else
> - stack_base = vma->vm_start - EXTRA_STACK_VM_PAGES * PAGE_SIZE;
> + if (stack_size + stack_expand > rlim_stack)
> + stack_base = vma->vm_end - rlim_stack;
> + else
> + stack_base = vma->vm_start - stack_expand;
> #endif
> ret = expand_stack(vma, stack_base);
> if (ret)
> _
>
^ permalink raw reply
* Re: [PATCH v4 3/3] powerpc: doc/dts-bindings: update doc of FSL I2C bindings
From: Grant Likely @ 2010-02-09 22:15 UTC (permalink / raw)
To: Wolfgang Grandegger
Cc: Wolfgang Grandegger, Devicetree-discuss, Linuxppc-dev, Linux-i2c,
Ben Dooks
In-Reply-To: <4B71B618.6020807@grandegger.com>
On Tue, Feb 9, 2010 at 12:23 PM, Wolfgang Grandegger <wg@grandegger.com> wr=
ote:
> Wolfgang Grandegger wrote:
>> Hi Grant,
>>
>> Grant Likely wrote:
>>> On Thu, Jan 28, 2010 at 6:25 AM, Wolfgang Grandegger <wg@grandegger.com=
> wrote:
>>>> From: Wolfgang Grandegger <wg@denx.de>
>>>>
>>>> This patch adds the MPC5121 to the list of supported devices,
>>>> enhances the doc of the "clock-frequency" property and removes
>>>> the obsolete "cell-index" property from the example nodes.
>>>> Furthermore and example for the MPC5121 has been added.
>>>>
>>>> Signed-off-by: Wolfgang Grandegger <wg@denx.de>
>>> Thanks Wolfgang. =A0Comments below.
>>>
>>>> ---
>>>> =A0Documentation/powerpc/dts-bindings/fsl/i2c.txt | =A0 30 +++++++++++=
++++++++----
>>>> =A01 files changed, 24 insertions(+), 6 deletions(-)
>>>>
>>>> diff --git a/Documentation/powerpc/dts-bindings/fsl/i2c.txt b/Document=
ation/powerpc/dts-bindings/fsl/i2c.txt
>>>> index b6d2e21..2f62dae 100644
>>>> --- a/Documentation/powerpc/dts-bindings/fsl/i2c.txt
>>>> +++ b/Documentation/powerpc/dts-bindings/fsl/i2c.txt
>>>> @@ -9,8 +9,9 @@ Recommended properties :
>>>>
>>>> =A0- compatible : compatibility list with 2 entries, the first should
>>>> =A0 =A0be "fsl,CHIP-i2c" where CHIP is the name of a compatible proces=
sor,
>>>> - =A0 e.g. mpc8313, mpc8543, mpc8544, mpc5200 or mpc5200b. The second =
one
>>>> - =A0 should be "fsl-i2c".
>>>> + =A0 e.g. mpc8313, mpc8543, mpc8544, mpc5121, mpc5200 or mpc5200b. Th=
e
>>>> + =A0 second one should be "fsl-i2c". For the mpc5121, an additional n=
ode
>>>> + =A0 "fsl,mpc5121-i2c-ctrl" is required as shown in the example below=
.
>>> While you're editing this line; drop the requirement for the second
>>> value to be 'fsl-i2c'. =A0We don't use it anymore, and only preserve it
>>> for backwards compatibility with old trees.
>>
>> OK.
>>
>>>> =A0- interrupts : <a b> where a is the interrupt number and b is a
>>>> =A0 =A0field that represents an encoding of the sense and level
>>>> =A0 =A0information for the interrupt. =A0This should be encoded based =
on
>>>> @@ -20,29 +21,46 @@ Recommended properties :
>>>> =A0 =A0services interrupts for this device.
>>>> =A0- fsl,preserve-clocking : boolean; if defined, the clock settings
>>>> =A0 =A0from the bootloader are preserved (not touched).
>>>> - - clock-frequency : desired I2C bus clock frequency in Hz.
>>>> + - clock-frequency : desired I2C bus clock frequency in Hz. =A0If thi=
s
>>>> + =A0 property and "fsl,preserve-clocking" is not defined, a safe fixe=
d
>>>> + =A0 clock divider value is used (resulting in a small clock frequenc=
y).
>>> Nah, leave this as is. =A0Don't make it sound like omitting both
>>> properties is a valid option. =A0The driver may (and should!) handle th=
e
>>> situation gracefully, but that fact does not need to be documented.
>>
>> The safe value is not a good choice, indeed. Then it will also change
>> MPC_I2C_CLOCK_SAFE to MPC_I2C_CLOCK_LEGACY in i2c-mpc.c.
>>
>> I will also fix the other issues you commented on.
>
> And I will also remove the "device_type" line from:
>
> =A0-------------
> =A0Required properties :
>
> =A0- device_type : Should be "i2c"
> =A0- reg : Offset and length of the register set for the device
Yes, please.
Hmmm. compatible should also be in the 'required properties' section.
Thanks,
g.
^ permalink raw reply
* Re: [PATCH v2 0/3] powerpc: mpc5121: PSC UART support
From: Grant Likely @ 2010-02-09 22:18 UTC (permalink / raw)
To: Anatolij Gustschin, Greg Kroah-Hartman
Cc: wd, dzu, gregkh, linux-kernel, linuxppc-dev
In-Reply-To: <1265750032-2803-1-git-send-email-agust@denx.de>
Greg, since this touches powerpc stuff, do you mind if I pick up the
series into my tree?
Thanks,
g.
On Tue, Feb 9, 2010 at 2:13 PM, Anatolij Gustschin <agust@denx.de> wrote:
> The support for mpc5121 PSC UART currently only works with
> serial console. This patch series re-enable PSC UART support for
> all 12 PSCs and document added DTS bingings.
>
> Anatolij Gustschin (3):
> =A0serial: mpc52xx_uart: re-enable mpc5121 PSC UART support
> =A0powerpc: doc/dts-bindings: document mpc5121 psc uart =A0dts-bindings
> =A0powerpc: mpc5121: enable support for more PSC UARTs
>
> =A0.../powerpc/dts-bindings/fsl/mpc5121-psc.txt =A0 =A0 =A0 | =A0 70 ++++=
++
> =A0arch/powerpc/include/asm/mpc52xx_psc.h =A0 =A0 =A0 =A0 =A0 =A0 | =A0 =
=A04 +
> =A0drivers/serial/mpc52xx_uart.c =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =
=A0| =A0251 ++++++++++++++++++--
> =A03 files changed, 310 insertions(+), 15 deletions(-)
> =A0create mode 100644 Documentation/powerpc/dts-bindings/fsl/mpc5121-psc.=
txt
>
>
--=20
Grant Likely, B.Sc., P.Eng.
Secret Lab Technologies Ltd.
^ permalink raw reply
* Re: [PATCH] Restrict initial stack space expansion to rlimit
From: Helge Deller @ 2010-02-09 22:27 UTC (permalink / raw)
To: Michael Neuling
Cc: linux-parisc, stable, aeb, Oleg Nesterov, miltonm, James Morris,
linuxppc-dev, Paul Mackerras, Anton Blanchard, KOSAKI Motohiro,
Serge Hallyn, linux-fsdevel, Americo Wang, Andrew Morton,
Linus Torvalds, Ingo Molnar, linux-kernel, Alexander Viro
In-Reply-To: <10733.1265752289@neuling.org>
On 02/09/2010 10:51 PM, Michael Neuling wrote:
>>> I'd still like someone with a CONFIG_STACK_GROWSUP arch to test/ACK it
>>> as well.
>>
>> There's only one CONFIG_GROWSUP arch - parisc.
>> Could someone please test it on parisc?
I did.
> How about doing:
> 'ulimit -s 15; ls'
> before and after the patch is applied. Before it's applied, 'ls' should
> be killed. After the patch is applied, 'ls' should no longer be killed.
>
> I'm suggesting a stack limit of 15KB since it's small enough to trigger
> 20*PAGE_SIZE. Also 15KB not a multiple of PAGE_SIZE, which is a trickier
> case to handle correctly with this code.
>
> 4K pages on parisc should be fine to test with.
Mikey, thanks for the suggested test plan.
I'm not sure if your patch does it correct for parisc/stack-grows-up-case.
I tested your patch on a 4k pages kernel:
root@c3000:~# uname -a
Linux c3000 2.6.33-rc7-32bit #221 Tue Feb 9 23:17:06 CET 2010 parisc GNU/Linux
Without your patch:
root@c3000:~# ulimit -s 15; ls
Killed
-> correct.
With your patch:
root@c3000:~# ulimit -s 15; ls
Killed
_or_:
root@c3000:~# ulimit -s 15; ls
Segmentation fault
-> ??
Any idea?
Helge
>> From: Michael Neuling<mikey@neuling.org>
>>
>> When reserving stack space for a new process, make sure we're not
>> attempting to expand the stack by more than rlimit allows.
>>
>> This fixes a bug caused by b6a2fea39318e43fee84fa7b0b90d68bed92d2ba ("mm:
>> variable length argument support") and unmasked by
>> fc63cf237078c86214abcb2ee9926d8ad289da9b ("exec: setup_arg_pages() fails
>> to return errors").
>>
>> This bug means that when limiting the stack to less the 20*PAGE_SIZE (eg.
>> 80K on 4K pages or 'ulimit -s 79') all processes will be killed before
>> they start. This is particularly bad with 64K pages, where a ulimit below
>> 1280K will kill every process.
>>
>> Signed-off-by: Michael Neuling<mikey@neuling.org>
>> Cc: KOSAKI Motohiro<kosaki.motohiro@jp.fujitsu.com>
>> Cc: Americo Wang<xiyou.wangcong@gmail.com>
>> Cc: Anton Blanchard<anton@samba.org>
>> Cc: Oleg Nesterov<oleg@redhat.com>
>> Cc: James Morris<jmorris@namei.org>
>> Cc: Ingo Molnar<mingo@elte.hu>
>> Cc: Serge Hallyn<serue@us.ibm.com>
>> Cc: Benjamin Herrenschmidt<benh@kernel.crashing.org>
>> Cc:<stable@kernel.org>
>>
>> fs/exec.c | 21 +++++++++++++++++++--
>> 1 file changed, 19 insertions(+), 2 deletions(-)
>>
>> diff -puN fs/exec.c~fs-execc-restrict-initial-stack-space-expansion-to-rlimit
> fs/exec.c
>> --- a/fs/exec.c~fs-execc-restrict-initial-stack-space-expansion-to-rlimit
>> +++ a/fs/exec.c
>> @@ -571,6 +571,9 @@ int setup_arg_pages(struct linux_binprm
>> struct vm_area_struct *prev = NULL;
>> unsigned long vm_flags;
>> unsigned long stack_base;
>> + unsigned long stack_size;
>> + unsigned long stack_expand;
>> + unsigned long rlim_stack;
>>
>> #ifdef CONFIG_STACK_GROWSUP
>> /* Limit stack size to 1GB */
>> @@ -627,10 +630,24 @@ int setup_arg_pages(struct linux_binprm
>> goto out_unlock;
>> }
>>
>> + stack_expand = EXTRA_STACK_VM_PAGES * PAGE_SIZE;
>> + stack_size = vma->vm_end - vma->vm_start;
>> + /*
>> + * Align this down to a page boundary as expand_stack
>> + * will align it up.
>> + */
>> + rlim_stack = rlimit(RLIMIT_STACK)& PAGE_MASK;
>> + rlim_stack = min(rlim_stack, stack_size);
>> #ifdef CONFIG_STACK_GROWSUP
>> - stack_base = vma->vm_end + EXTRA_STACK_VM_PAGES * PAGE_SIZE;
>> + if (stack_size + stack_expand> rlim_stack)
>> + stack_base = vma->vm_start + rlim_stack;
>> + else
>> + stack_base = vma->vm_end + stack_expand;
>> #else
>> - stack_base = vma->vm_start - EXTRA_STACK_VM_PAGES * PAGE_SIZE;
>> + if (stack_size + stack_expand> rlim_stack)
>> + stack_base = vma->vm_end - rlim_stack;
>> + else
>> + stack_base = vma->vm_start - stack_expand;
>> #endif
>> ret = expand_stack(vma, stack_base);
>> if (ret)
^ permalink raw reply
* Re: [PATCH] [V3] net: emaclite: adding MDIO and phy lib support
From: John Williams @ 2010-02-09 22:30 UTC (permalink / raw)
To: John Linn; +Cc: Sadanand Mutyala, netdev, linuxppc-dev, jgarzik
In-Reply-To: <2ea396ca-3014-40f4-86ac-0e9f1aa82b5b@SG2EHSMHS005.ehs.local>
Hi John,
Sorry If I'm painting bike-sheds here, just one tiny tweak might be in
order to standardise your mutex_unlock exit path:
> +static int xemaclite_mdio_read(struct mii_bus *bus, int phy_id, int reg)
> +{
> + =A0 =A0 =A0 struct net_local *lp =3D bus->priv;
> + =A0 =A0 =A0 u32 ctrl_reg;
> + =A0 =A0 =A0 u32 rc;
> +
> + =A0 =A0 =A0 mutex_lock(&lp->mdio_mutex);
> +
> + =A0 =A0 =A0 if (xemaclite_mdio_wait(lp)) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 mutex_unlock(&lp->mdio_mutex);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 return -ETIMEDOUT;
> + =A0 =A0 =A0 }
[snip]
> + =A0 =A0 =A0 if (xemaclite_mdio_wait(lp)) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 mutex_unlock(&lp->mdio_mutex);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 return -ETIMEDOUT;
> + =A0 =A0 =A0 }
[snip]
> + =A0 =A0 =A0 dev_dbg(&lp->ndev->dev,
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 "xemaclite_mdio_read(phy_id=3D%i, reg=3D%x)=
=3D=3D %x\n",
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 phy_id, reg, rc);
> +
> + =A0 =A0 =A0 return rc;
Can this be better expressed like this:
my_func() {
mutex_lock()
..
if(some error) {
rc=3D-ETIMEDOUT;
goto out_unlock;
}
...
/* success path */
rc=3D0;
..
out_unlock:
mutex_unlock()
return rc;
}
Is this style still favoured in driver exit paths?
Thanks,
John
--=20
John Williams, PhD, B.Eng, B.IT
PetaLogix - Linux Solutions for a Reconfigurable World
w: www.petalogix.com p: +61-7-30090663 f: +61-7-30090663
^ permalink raw reply
* RE: [PATCH] [V3] net: emaclite: adding MDIO and phy lib support
From: John Linn @ 2010-02-09 22:38 UTC (permalink / raw)
To: John Williams; +Cc: linuxppc-dev, netdev, Sadanand Mutyala, jgarzik
In-Reply-To: <1d3f23371002091430hb550153u602c8e7c010381b9@mail.gmail.com>
> -----Original Message-----
> From: John Williams [mailto:john.williams@petalogix.com]
> Sent: Tuesday, February 09, 2010 3:30 PM
> To: John Linn
> Cc: netdev@vger.kernel.org; linuxppc-dev@ozlabs.org; jgarzik@pobox.com; g=
rant.likely@secretlab.ca;
> jwboyer@linux.vnet.ibm.com; Sadanand Mutyala
> Subject: Re: [PATCH] [V3] net: emaclite: adding MDIO and phy lib support
> =
> Hi John,
> =
> Sorry If I'm painting bike-sheds here, just one tiny tweak might be in
> order to standardise your mutex_unlock exit path:
Hey John, I prefer burning down bike-sheds myself, fire and explosions are =
always more fun than painting :)
> =
> > +static int xemaclite_mdio_read(struct mii_bus *bus, int phy_id, int re=
g)
> > +{
> > + =A0 =A0 =A0 struct net_local *lp =3D bus->priv;
> > + =A0 =A0 =A0 u32 ctrl_reg;
> > + =A0 =A0 =A0 u32 rc;
> > +
> > + =A0 =A0 =A0 mutex_lock(&lp->mdio_mutex);
> > +
> > + =A0 =A0 =A0 if (xemaclite_mdio_wait(lp)) {
> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 mutex_unlock(&lp->mdio_mutex);
> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 return -ETIMEDOUT;
> > + =A0 =A0 =A0 }
> =
> [snip]
> =
> =
> > + =A0 =A0 =A0 if (xemaclite_mdio_wait(lp)) {
> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 mutex_unlock(&lp->mdio_mutex);
> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 return -ETIMEDOUT;
> > + =A0 =A0 =A0 }
> =
> [snip]
> =
> =
> > + =A0 =A0 =A0 dev_dbg(&lp->ndev->dev,
> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 "xemaclite_mdio_read(phy_id=3D%i, reg=3D%=
x) =3D=3D %x\n",
> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 phy_id, reg, rc);
> > +
> > + =A0 =A0 =A0 return rc;
> =
> Can this be better expressed like this:
> =
> my_func() {
> mutex_lock()
> ..
> =
> if(some error) {
> rc=3D-ETIMEDOUT;
> goto out_unlock;
> }
> ...
> =
> /* success path */
> rc=3D0;
> ..
> out_unlock:
> mutex_unlock()
> return rc;
> }
> =
> =
> Is this style still favoured in driver exit paths?
I considered that and then blew it off (maybe shouldn't have). =
If we think it's a more std way to do it then no big deal. I'll see if the=
re are any other comments before spinning another maybe final patch.
Thanks for the input,
John
> =
> Thanks,
> =
> John
> --
> John Williams, PhD, B.Eng, B.IT
> PetaLogix - Linux Solutions for a Reconfigurable World
> w: www.petalogix.com p: +61-7-30090663 f: +61-7-30090663
This email and any attachments are intended for the sole use of the named r=
ecipient(s) and contain(s) confidential information that may be proprietary=
, privileged or copyrighted under applicable law. If you are not the intend=
ed recipient, do not read, copy, or forward this email message or any attac=
hments. Delete this email message and any attachments immediately.
^ permalink raw reply
* Re: [PATCH v2 0/3] powerpc: mpc5121: PSC UART support
From: Greg KH @ 2010-02-09 22:38 UTC (permalink / raw)
To: Grant Likely
Cc: wd, dzu, gregkh, linux-kernel, linuxppc-dev, Anatolij Gustschin
In-Reply-To: <fa686aa41002091418q2e97919ft2bcf8ad02e050afa@mail.gmail.com>
On Tue, Feb 09, 2010 at 03:18:57PM -0700, Grant Likely wrote:
> Greg, since this touches powerpc stuff, do you mind if I pick up the
> series into my tree?
No objection at all, feel free to add an:
Acked-by: Greg Kroah-Hartman <gregkh@suse.de>
to the patches.
thanks,
greg k-h
^ permalink raw reply
* RE: [PATCH] [V3] net: emaclite: adding MDIO and phy lib support
From: John Linn @ 2010-02-09 23:00 UTC (permalink / raw)
To: John Williams; +Cc: linuxppc-dev, netdev, Sadanand Mutyala, jgarzik
In-Reply-To: <1d3f23371002091430hb550153u602c8e7c010381b9@mail.gmail.com>
> -----Original Message-----
> From: John Williams [mailto:john.williams@petalogix.com]
> Sent: Tuesday, February 09, 2010 3:30 PM
> To: John Linn
> Cc: netdev@vger.kernel.org; linuxppc-dev@ozlabs.org; jgarzik@pobox.com; g=
rant.likely@secretlab.ca;
> jwboyer@linux.vnet.ibm.com; Sadanand Mutyala
> Subject: Re: [PATCH] [V3] net: emaclite: adding MDIO and phy lib support
> =
> Hi John,
> =
> Sorry If I'm painting bike-sheds here, just one tiny tweak might be in
> order to standardise your mutex_unlock exit path:
> =
> > +static int xemaclite_mdio_read(struct mii_bus *bus, int phy_id, int re=
g)
> > +{
> > + =A0 =A0 =A0 struct net_local *lp =3D bus->priv;
> > + =A0 =A0 =A0 u32 ctrl_reg;
> > + =A0 =A0 =A0 u32 rc;
> > +
> > + =A0 =A0 =A0 mutex_lock(&lp->mdio_mutex);
> > +
> > + =A0 =A0 =A0 if (xemaclite_mdio_wait(lp)) {
> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 mutex_unlock(&lp->mdio_mutex);
> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 return -ETIMEDOUT;
> > + =A0 =A0 =A0 }
> =
> [snip]
> =
> =
> > + =A0 =A0 =A0 if (xemaclite_mdio_wait(lp)) {
> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 mutex_unlock(&lp->mdio_mutex);
> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 return -ETIMEDOUT;
> > + =A0 =A0 =A0 }
> =
> [snip]
> =
> =
> > + =A0 =A0 =A0 dev_dbg(&lp->ndev->dev,
> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 "xemaclite_mdio_read(phy_id=3D%i, reg=3D%=
x) =3D=3D %x\n",
> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 phy_id, reg, rc);
> > +
> > + =A0 =A0 =A0 return rc;
> =
> Can this be better expressed like this:
> =
> my_func() {
> mutex_lock()
> ..
> =
> if(some error) {
> rc=3D-ETIMEDOUT;
> goto out_unlock;
> }
> ...
> =
> /* success path */
> rc=3D0;
> ..
> out_unlock:
> mutex_unlock()
> return rc;
> }
> =
> =
> Is this style still favoured in driver exit paths?
It looks to me like the mutex is not needed in the driver mdio functions as=
there's a mutex in the mdiobus functions already.
Am I wrong about that?
Thanks,
John
>From phy/mdio_bus.c
int mdiobus_read(struct mii_bus *bus, int addr, u16 regnum)
{
int retval;
BUG_ON(in_interrupt());
mutex_lock(&bus->mdio_lock);
retval =3D bus->read(bus, addr, regnum);
mutex_unlock(&bus->mdio_lock);
return retval;
}
EXPORT_SYMBOL(mdiobus_read);
int mdiobus_write(struct mii_bus *bus, int addr, u16 regnum, u16 val)
{
int err;
BUG_ON(in_interrupt());
mutex_lock(&bus->mdio_lock);
err =3D bus->write(bus, addr, regnum, val);
mutex_unlock(&bus->mdio_lock);
return err;
}
EXPORT_SYMBOL(mdiobus_write);
> =
> Thanks,
> =
> John
> --
> John Williams, PhD, B.Eng, B.IT
> PetaLogix - Linux Solutions for a Reconfigurable World
> w: www.petalogix.com p: +61-7-30090663 f: +61-7-30090663
This email and any attachments are intended for the sole use of the named r=
ecipient(s) and contain(s) confidential information that may be proprietary=
, privileged or copyrighted under applicable law. If you are not the intend=
ed recipient, do not read, copy, or forward this email message or any attac=
hments. Delete this email message and any attachments immediately.
^ permalink raw reply
* Re: [PATCH v3 02/11] powerpc/mpc5121: Add machine restart support
From: Wolfram Sang @ 2010-02-09 23:24 UTC (permalink / raw)
To: Anatolij Gustschin; +Cc: linuxppc-dev, wd, dzu, Piotr Ziecik
In-Reply-To: <1265377377-29327-3-git-send-email-agust@denx.de>
[-- Attachment #1: Type: text/plain, Size: 5161 bytes --]
Hi,
On Fri, Feb 05, 2010 at 02:42:48PM +0100, Anatolij Gustschin wrote:
> Add reset module registers representation and
> machine restart callback for mpc5121 platform.
>
Two comments:
> Signed-off-by: Piotr Ziecik <kosmo@semihalf.com>
> Signed-off-by: Wolfgang Denk <wd@denx.de>
> Signed-off-by: Anatolij Gustschin <agust@denx.de>
> Cc: Grant Likely <grant.likely@secretlab.ca>
> Cc: John Rigby <jcrigby@gmail.com>
> ---
> Changes since v2:
> - call mpc512x_restart_init() explicitely from platform
> init code
>
> Changes since v1:
> - use 'struct mpc512x_reset_module *' type for 'reset_module_base'
> - remove empty line
> - remove leftover colon and use pr_err() instead of printk.
>
> arch/powerpc/include/asm/mpc5xxx.h | 14 +++++++++-
> arch/powerpc/platforms/512x/mpc5121_ads.c | 1 +
> arch/powerpc/platforms/512x/mpc5121_generic.c | 1 +
> arch/powerpc/platforms/512x/mpc512x.h | 1 +
> arch/powerpc/platforms/512x/mpc512x_shared.c | 34 +++++++++++++++++++++++++
> 5 files changed, 50 insertions(+), 1 deletions(-)
>
> diff --git a/arch/powerpc/include/asm/mpc5xxx.h b/arch/powerpc/include/asm/mpc5xxx.h
> index 5ce9c5f..0004986 100644
> --- a/arch/powerpc/include/asm/mpc5xxx.h
> +++ b/arch/powerpc/include/asm/mpc5xxx.h
> @@ -18,5 +18,17 @@
>
> extern unsigned long mpc5xxx_get_bus_frequency(struct device_node *node);
>
> -#endif /* __ASM_POWERPC_MPC5xxx_H__ */
> +/* MPC512x Reset module registers */
> +struct mpc512x_reset_module {
> + u32 rcwlr; /* Reset Configuration Word Low Register */
> + u32 rcwhr; /* Reset Configuration Word High Register */
> + u32 reserved1;
> + u32 reserved2;
> + u32 rsr; /* Reset Status Register */
> + u32 rmr; /* Reset Mode Register */
> + u32 rpr; /* Reset Protection Register */
> + u32 rcr; /* Reset Control Register */
> + u32 rcer; /* Reset Control Enable Register */
> +};
>
> +#endif /* __ASM_POWERPC_MPC5xxx_H__ */
> diff --git a/arch/powerpc/platforms/512x/mpc5121_ads.c b/arch/powerpc/platforms/512x/mpc5121_ads.c
> index 0f8f2e9..ee6ae12 100644
> --- a/arch/powerpc/platforms/512x/mpc5121_ads.c
> +++ b/arch/powerpc/platforms/512x/mpc5121_ads.c
> @@ -68,4 +68,5 @@ define_machine(mpc5121_ads) {
> .init_IRQ = mpc5121_ads_init_IRQ,
> .get_irq = ipic_get_irq,
> .calibrate_decr = generic_calibrate_decr,
> + .restart = mpc512x_restart,
> };
> diff --git a/arch/powerpc/platforms/512x/mpc5121_generic.c b/arch/powerpc/platforms/512x/mpc5121_generic.c
> index 9b8c9b0..a6c0e3a 100644
> --- a/arch/powerpc/platforms/512x/mpc5121_generic.c
> +++ b/arch/powerpc/platforms/512x/mpc5121_generic.c
> @@ -55,4 +55,5 @@ define_machine(mpc5121_generic) {
> .init_IRQ = mpc512x_init_IRQ,
> .get_irq = ipic_get_irq,
> .calibrate_decr = generic_calibrate_decr,
> + .restart = mpc512x_restart,
> };
> diff --git a/arch/powerpc/platforms/512x/mpc512x.h b/arch/powerpc/platforms/512x/mpc512x.h
> index ac3da1a..b2daca0 100644
> --- a/arch/powerpc/platforms/512x/mpc512x.h
> +++ b/arch/powerpc/platforms/512x/mpc512x.h
> @@ -15,4 +15,5 @@ extern void __init mpc512x_init_IRQ(void);
> extern void __init mpc512x_init(void);
> extern int __init mpc5121_clk_init(void);
> void __init mpc512x_declare_of_platform_devices(void);
> +extern void mpc512x_restart(char *cmd);
> #endif /* __MPC512X_H__ */
> diff --git a/arch/powerpc/platforms/512x/mpc512x_shared.c b/arch/powerpc/platforms/512x/mpc512x_shared.c
> index b683165..ac0400e 100644
> --- a/arch/powerpc/platforms/512x/mpc512x_shared.c
> +++ b/arch/powerpc/platforms/512x/mpc512x_shared.c
> @@ -21,9 +21,42 @@
> #include <asm/ipic.h>
> #include <asm/prom.h>
> #include <asm/time.h>
> +#include <asm/mpc5xxx.h>
>
> #include "mpc512x.h"
>
> +static struct mpc512x_reset_module __iomem *reset_module_base;
> +
> +static int __init mpc512x_restart_init(void)
> +{
> + struct device_node *np;
> +
> + np = of_find_compatible_node(NULL, NULL, "fsl,mpc5121-reset");
> + if (!np)
> + return -1;
> +
> + reset_module_base = of_iomap(np, 0);
> + of_node_put(np);
> +
> + return 0;
> +}
> +
> +void mpc512x_restart(char *cmd)
> +{
> + struct mpc512x_reset_module *rm = reset_module_base;
Why not using reset_module_base directly?
> +
> + if (rm) {
> + /* Enable software reset "RSTE" */
> + out_be32(&rm->rpr, 0x52535445);
> + /* Set software hard reset */
> + out_be32(&rm->rcr, 0x2);
> + } else {
> + pr_err("Restart module not mapped.\n");
> + }
> + for (;;)
> + ;
> +}
> +
> void __init mpc512x_init_IRQ(void)
> {
> struct device_node *np;
> @@ -62,4 +95,5 @@ void __init mpc512x_init(void)
> {
> mpc512x_declare_of_platform_devices();
> mpc5121_clk_init();
> + mpc512x_restart_init();
If the return value is not checked here, you could as well make the function
void. (Not much one could do in the error-case, too.)
> }
> --
Regards,
Wolfram
--
Pengutronix e.K. | Wolfram Sang |
Industrial Linux Solutions | http://www.pengutronix.de/ |
[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 197 bytes --]
^ permalink raw reply
* Re: [PATCH] [V3] net: emaclite: adding MDIO and phy lib support
From: Grant Likely @ 2010-02-10 1:53 UTC (permalink / raw)
To: John Linn; +Cc: linuxppc-dev, netdev, Sadanand Mutyala, jgarzik, John Williams
In-Reply-To: <ad1b9321-b7ad-47a6-93ca-ca260ff2a66d@SG2EHSMHS011.ehs.local>
On Tue, Feb 9, 2010 at 4:00 PM, John Linn <John.Linn@xilinx.com> wrote:
>> -----Original Message-----
>> From: John Williams [mailto:john.williams@petalogix.com]
>> Sent: Tuesday, February 09, 2010 3:30 PM
>> To: John Linn
>> Cc: netdev@vger.kernel.org; linuxppc-dev@ozlabs.org; jgarzik@pobox.com; =
grant.likely@secretlab.ca;
>> jwboyer@linux.vnet.ibm.com; Sadanand Mutyala
>> Subject: Re: [PATCH] [V3] net: emaclite: adding MDIO and phy lib support
>>
>> Hi John,
>>
>> Sorry If I'm painting bike-sheds here, just one tiny tweak might be in
>> order to standardise your mutex_unlock exit path:
>>
>> > +static int xemaclite_mdio_read(struct mii_bus *bus, int phy_id, int r=
eg)
>> > +{
>> > + =A0 =A0 =A0 struct net_local *lp =3D bus->priv;
>> > + =A0 =A0 =A0 u32 ctrl_reg;
>> > + =A0 =A0 =A0 u32 rc;
>> > +
>> > + =A0 =A0 =A0 mutex_lock(&lp->mdio_mutex);
>> > +
>> > + =A0 =A0 =A0 if (xemaclite_mdio_wait(lp)) {
>> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 mutex_unlock(&lp->mdio_mutex);
>> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 return -ETIMEDOUT;
>> > + =A0 =A0 =A0 }
>>
>> [snip]
>>
>>
>> > + =A0 =A0 =A0 if (xemaclite_mdio_wait(lp)) {
>> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 mutex_unlock(&lp->mdio_mutex);
>> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 return -ETIMEDOUT;
>> > + =A0 =A0 =A0 }
>>
>> [snip]
>>
>>
>> > + =A0 =A0 =A0 dev_dbg(&lp->ndev->dev,
>> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 "xemaclite_mdio_read(phy_id=3D%i, reg=3D=
%x) =3D=3D %x\n",
>> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 phy_id, reg, rc);
>> > +
>> > + =A0 =A0 =A0 return rc;
>>
>> Can this be better expressed like this:
>>
>> my_func() {
>> =A0 mutex_lock()
>> ..
>>
>> =A0 if(some error) {
>> =A0 =A0 rc=3D-ETIMEDOUT;
>> =A0 =A0 goto out_unlock;
>> =A0 }
>> =A0 ...
>>
>> =A0 /* success path */
>> =A0 rc=3D0;
>> ..
>> out_unlock:
>> =A0 mutex_unlock()
>> =A0 return rc;
>> }
>>
>>
>> Is this style still favoured in driver exit paths?
>
> It looks to me like the mutex is not needed in the driver mdio functions =
as there's a mutex in the mdiobus functions already.
Yes, you're correct, but you still need to protect against direct
calls to the read/write routines from within the driver. But you can
probably use the mdio_lock mutex for this.
g.
^ permalink raw reply
* Re: [PATCH v3 02/11] powerpc/mpc5121: Add machine restart support
From: Grant Likely @ 2010-02-10 2:32 UTC (permalink / raw)
To: Anatolij Gustschin; +Cc: linuxppc-dev, wd, dzu, Piotr Ziecik
In-Reply-To: <1265377377-29327-3-git-send-email-agust@denx.de>
On Fri, Feb 5, 2010 at 6:42 AM, Anatolij Gustschin <agust@denx.de> wrote:
> Add reset module registers representation and
> machine restart callback for mpc5121 platform.
>
> Signed-off-by: Piotr Ziecik <kosmo@semihalf.com>
> Signed-off-by: Wolfgang Denk <wd@denx.de>
> Signed-off-by: Anatolij Gustschin <agust@denx.de>
> Cc: Grant Likely <grant.likely@secretlab.ca>
> Cc: John Rigby <jcrigby@gmail.com>
> ---
> Changes since v2:
> =A0- call mpc512x_restart_init() explicitely from platform
> =A0 init code
>
> Changes since v1:
> =A0- use 'struct mpc512x_reset_module *' type for 'reset_module_base'
> =A0- remove empty line
> =A0- remove leftover colon and use pr_err() instead of printk.
>
> =A0arch/powerpc/include/asm/mpc5xxx.h =A0 =A0 =A0 =A0 =A0 =A0| =A0 14 +++=
++++++-
> =A0arch/powerpc/platforms/512x/mpc5121_ads.c =A0 =A0 | =A0 =A01 +
> =A0arch/powerpc/platforms/512x/mpc5121_generic.c | =A0 =A01 +
> =A0arch/powerpc/platforms/512x/mpc512x.h =A0 =A0 =A0 =A0 | =A0 =A01 +
> =A0arch/powerpc/platforms/512x/mpc512x_shared.c =A0| =A0 34 +++++++++++++=
++++++++++++
> =A05 files changed, 50 insertions(+), 1 deletions(-)
>
> diff --git a/arch/powerpc/include/asm/mpc5xxx.h b/arch/powerpc/include/as=
m/mpc5xxx.h
> index 5ce9c5f..0004986 100644
> --- a/arch/powerpc/include/asm/mpc5xxx.h
> +++ b/arch/powerpc/include/asm/mpc5xxx.h
> @@ -18,5 +18,17 @@
>
> =A0extern unsigned long mpc5xxx_get_bus_frequency(struct device_node *nod=
e);
>
> -#endif /* __ASM_POWERPC_MPC5xxx_H__ */
> +/* MPC512x Reset module registers */
> +struct mpc512x_reset_module {
> + =A0 =A0 =A0 u32 =A0 =A0 rcwlr; =A0/* Reset Configuration Word Low Regis=
ter */
> + =A0 =A0 =A0 u32 =A0 =A0 rcwhr; =A0/* Reset Configuration Word High Regi=
ster */
> + =A0 =A0 =A0 u32 =A0 =A0 reserved1;
> + =A0 =A0 =A0 u32 =A0 =A0 reserved2;
> + =A0 =A0 =A0 u32 =A0 =A0 rsr; =A0 =A0/* Reset Status Register */
> + =A0 =A0 =A0 u32 =A0 =A0 rmr; =A0 =A0/* Reset Mode Register */
> + =A0 =A0 =A0 u32 =A0 =A0 rpr; =A0 =A0/* Reset Protection Register */
> + =A0 =A0 =A0 u32 =A0 =A0 rcr; =A0 =A0/* Reset Control Register */
> + =A0 =A0 =A0 u32 =A0 =A0 rcer; =A0 /* Reset Control Enable Register */
> +};
This isn't useful for 5200. Create a new file.
arch/powerpc/include/asm/mpc5121.h
g.
^ permalink raw reply
* Re: [PATCH v3 03/11] rtc: Add MPC5121 Real time clock driver
From: Grant Likely @ 2010-02-10 2:39 UTC (permalink / raw)
To: Anatolij Gustschin, Alessandro Zummo
Cc: wd, rtc-linux, linuxppc-dev, dzu, Piotr Ziecik
In-Reply-To: <1265377377-29327-4-git-send-email-agust@denx.de>
On Fri, Feb 5, 2010 at 6:42 AM, Anatolij Gustschin <agust@denx.de> wrote:
> Add support for MPC5121 real time clock module.
>
> Signed-off-by: John Rigby <jcrigby@gmail.com>
> Signed-off-by: Piotr Ziecik <kosmo@semihalf.com>
> Signed-off-by: Wolfgang Denk <wd@denx.de>
> Signed-off-by: Anatolij Gustschin <agust@denx.de>
> Cc: <rtc-linux@googlegroups.com>
> Cc: Grant Likely <grant.likely@secretlab.ca>
> Cc: John Rigby <jcrigby@gmail.com>
Acked-by: Grant Likely <grant.likely@secretlab.ca>
Alessandro, do you want me to carry this one in my powerpc tree along
with the rest of the 5121 patches, or do you want to carry it? There
aren't any commit ordering issues on this one.
g.
> ---
>
> Changes since v2:
> =A0- change commit message to describe what the patch is
> =A0- use __devinit/__devexit/__devexit_p for the probe/remove hooks
> =A0 and __devinitdata for the match table
> =A0- register device after it is completely set up
>
> Changes since v1 (as requested by Alessandro Zummo):
> =A0- Remove history from the driver file, the same history is in
> =A0 commit message
> =A0- implement alarm/irq interface using ->ops structure, don't
> =A0 use ops->ioctl() any more
> =A0- Clean up probe()
> =A0- replace printk() by dev_*()
> =A0- add arch dependency in Kconfig
> =A0- add requested include linux/init.h
> =A0- move MODULE_XXX to the end
> =A0- use rtc_valid_tm() when returning 'tm'
> =A0- use __init/__exit/__exit_p as this is not a hotpluggable device
>
> =A0drivers/rtc/Kconfig =A0 =A0 =A0 | =A0 10 ++
> =A0drivers/rtc/Makefile =A0 =A0 =A0| =A0 =A01 +
> =A0drivers/rtc/rtc-mpc5121.c | =A0387 +++++++++++++++++++++++++++++++++++=
++++++++++
> =A03 files changed, 398 insertions(+), 0 deletions(-)
> =A0create mode 100644 drivers/rtc/rtc-mpc5121.c
>
> diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
> index 8167e9e..2bb8a8b 100644
> --- a/drivers/rtc/Kconfig
> +++ b/drivers/rtc/Kconfig
> @@ -868,4 +868,14 @@ config RTC_DRV_MC13783
> =A0 =A0 =A0 =A0help
> =A0 =A0 =A0 =A0 =A0This enables support for the Freescale MC13783 PMIC RT=
C
>
> +config RTC_DRV_MPC5121
> + =A0 =A0 =A0 tristate "Freescale MPC5121 built-in RTC"
> + =A0 =A0 =A0 depends on PPC_MPC512x && RTC_CLASS
> + =A0 =A0 =A0 help
> + =A0 =A0 =A0 =A0 If you say yes here you will get support for the
> + =A0 =A0 =A0 =A0 built-in RTC MPC5121.
> +
> + =A0 =A0 =A0 =A0 This driver can also be built as a module. If so, the m=
odule
> + =A0 =A0 =A0 =A0 will be called rtc-mpc5121.
> +
> =A0endif # RTC_CLASS
> diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile
> index e5160fd..b7148af 100644
> --- a/drivers/rtc/Makefile
> +++ b/drivers/rtc/Makefile
> @@ -55,6 +55,7 @@ obj-$(CONFIG_RTC_DRV_MAX6900) +=3D rtc-max6900.o
> =A0obj-$(CONFIG_RTC_DRV_MAX6902) =A0+=3D rtc-max6902.o
> =A0obj-$(CONFIG_RTC_DRV_MC13783) =A0+=3D rtc-mc13783.o
> =A0obj-$(CONFIG_RTC_DRV_MSM6242) =A0+=3D rtc-msm6242.o
> +obj-$(CONFIG_RTC_DRV_MPC5121) =A0+=3D rtc-mpc5121.o
> =A0obj-$(CONFIG_RTC_DRV_MV) =A0 =A0 =A0 +=3D rtc-mv.o
> =A0obj-$(CONFIG_RTC_DRV_NUC900) =A0 +=3D rtc-nuc900.o
> =A0obj-$(CONFIG_RTC_DRV_OMAP) =A0 =A0 +=3D rtc-omap.o
> diff --git a/drivers/rtc/rtc-mpc5121.c b/drivers/rtc/rtc-mpc5121.c
> new file mode 100644
> index 0000000..4313ca0
> --- /dev/null
> +++ b/drivers/rtc/rtc-mpc5121.c
> @@ -0,0 +1,387 @@
> +/*
> + * Real-time clock driver for MPC5121
> + *
> + * Copyright 2007, Domen Puncer <domen.puncer@telargo.com>
> + * Copyright 2008, Freescale Semiconductor, Inc. All rights reserved.
> + *
> + * 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.
> + */
> +
> +#include <linux/init.h>
> +#include <linux/module.h>
> +#include <linux/rtc.h>
> +#include <linux/of_device.h>
> +#include <linux/of_platform.h>
> +#include <linux/io.h>
> +
> +struct mpc5121_rtc_regs {
> + =A0 =A0 =A0 u8 set_time; =A0 =A0 =A0 =A0 =A0 =A0/* RTC + 0x00 */
> + =A0 =A0 =A0 u8 hour_set; =A0 =A0 =A0 =A0 =A0 =A0/* RTC + 0x01 */
> + =A0 =A0 =A0 u8 minute_set; =A0 =A0 =A0 =A0 =A0/* RTC + 0x02 */
> + =A0 =A0 =A0 u8 second_set; =A0 =A0 =A0 =A0 =A0/* RTC + 0x03 */
> +
> + =A0 =A0 =A0 u8 set_date; =A0 =A0 =A0 =A0 =A0 =A0/* RTC + 0x04 */
> + =A0 =A0 =A0 u8 month_set; =A0 =A0 =A0 =A0 =A0 /* RTC + 0x05 */
> + =A0 =A0 =A0 u8 weekday_set; =A0 =A0 =A0 =A0 /* RTC + 0x06 */
> + =A0 =A0 =A0 u8 date_set; =A0 =A0 =A0 =A0 =A0 =A0/* RTC + 0x07 */
> +
> + =A0 =A0 =A0 u8 write_sw; =A0 =A0 =A0 =A0 =A0 =A0/* RTC + 0x08 */
> + =A0 =A0 =A0 u8 sw_set; =A0 =A0 =A0 =A0 =A0 =A0 =A0/* RTC + 0x09 */
> + =A0 =A0 =A0 u16 year_set; =A0 =A0 =A0 =A0 =A0 /* RTC + 0x0a */
> +
> + =A0 =A0 =A0 u8 alm_enable; =A0 =A0 =A0 =A0 =A0/* RTC + 0x0c */
> + =A0 =A0 =A0 u8 alm_hour_set; =A0 =A0 =A0 =A0/* RTC + 0x0d */
> + =A0 =A0 =A0 u8 alm_min_set; =A0 =A0 =A0 =A0 /* RTC + 0x0e */
> + =A0 =A0 =A0 u8 int_enable; =A0 =A0 =A0 =A0 =A0/* RTC + 0x0f */
> +
> + =A0 =A0 =A0 u8 reserved1;
> + =A0 =A0 =A0 u8 hour; =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0/* RTC + 0x11 */
> + =A0 =A0 =A0 u8 minute; =A0 =A0 =A0 =A0 =A0 =A0 =A0/* RTC + 0x12 */
> + =A0 =A0 =A0 u8 second; =A0 =A0 =A0 =A0 =A0 =A0 =A0/* RTC + 0x13 */
> +
> + =A0 =A0 =A0 u8 month; =A0 =A0 =A0 =A0 =A0 =A0 =A0 /* RTC + 0x14 */
> + =A0 =A0 =A0 u8 wday_mday; =A0 =A0 =A0 =A0 =A0 /* RTC + 0x15 */
> + =A0 =A0 =A0 u16 year; =A0 =A0 =A0 =A0 =A0 =A0 =A0 /* RTC + 0x16 */
> +
> + =A0 =A0 =A0 u8 int_alm; =A0 =A0 =A0 =A0 =A0 =A0 /* RTC + 0x18 */
> + =A0 =A0 =A0 u8 int_sw; =A0 =A0 =A0 =A0 =A0 =A0 =A0/* RTC + 0x19 */
> + =A0 =A0 =A0 u8 alm_status; =A0 =A0 =A0 =A0 =A0/* RTC + 0x1a */
> + =A0 =A0 =A0 u8 sw_minute; =A0 =A0 =A0 =A0 =A0 /* RTC + 0x1b */
> +
> + =A0 =A0 =A0 u8 bus_error_1; =A0 =A0 =A0 =A0 /* RTC + 0x1c */
> + =A0 =A0 =A0 u8 int_day; =A0 =A0 =A0 =A0 =A0 =A0 /* RTC + 0x1d */
> + =A0 =A0 =A0 u8 int_min; =A0 =A0 =A0 =A0 =A0 =A0 /* RTC + 0x1e */
> + =A0 =A0 =A0 u8 int_sec; =A0 =A0 =A0 =A0 =A0 =A0 /* RTC + 0x1f */
> +
> + =A0 =A0 =A0 /*
> + =A0 =A0 =A0 =A0* target_time:
> + =A0 =A0 =A0 =A0* =A0 =A0 =A0intended to be used for hibernation but hib=
ernation
> + =A0 =A0 =A0 =A0* =A0 =A0 =A0does not work on silicon rev 1.5 so use it =
for non-volatile
> + =A0 =A0 =A0 =A0* =A0 =A0 =A0storage of offset between the actual_time r=
egister and linux
> + =A0 =A0 =A0 =A0* =A0 =A0 =A0time
> + =A0 =A0 =A0 =A0*/
> + =A0 =A0 =A0 u32 target_time; =A0 =A0 =A0 =A0/* RTC + 0x20 */
> + =A0 =A0 =A0 /*
> + =A0 =A0 =A0 =A0* actual_time:
> + =A0 =A0 =A0 =A0* =A0 =A0 =A0readonly time since VBAT_RTC was last conne=
cted
> + =A0 =A0 =A0 =A0*/
> + =A0 =A0 =A0 u32 actual_time; =A0 =A0 =A0 =A0/* RTC + 0x24 */
> + =A0 =A0 =A0 u32 keep_alive; =A0 =A0 =A0 =A0 /* RTC + 0x28 */
> +};
> +
> +struct mpc5121_rtc_data {
> + =A0 =A0 =A0 unsigned irq;
> + =A0 =A0 =A0 unsigned irq_periodic;
> + =A0 =A0 =A0 struct mpc5121_rtc_regs __iomem *regs;
> + =A0 =A0 =A0 struct rtc_device *rtc;
> + =A0 =A0 =A0 struct rtc_wkalrm wkalarm;
> +};
> +
> +/*
> + * Update second/minute/hour registers.
> + *
> + * This is just so alarm will work.
> + */
> +static void mpc5121_rtc_update_smh(struct mpc5121_rtc_regs __iomem *regs=
,
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0stru=
ct rtc_time *tm)
> +{
> + =A0 =A0 =A0 out_8(®s->second_set, tm->tm_sec);
> + =A0 =A0 =A0 out_8(®s->minute_set, tm->tm_min);
> + =A0 =A0 =A0 out_8(®s->hour_set, tm->tm_hour);
> +
> + =A0 =A0 =A0 /* set time sequence */
> + =A0 =A0 =A0 out_8(®s->set_time, 0x1);
> + =A0 =A0 =A0 out_8(®s->set_time, 0x3);
> + =A0 =A0 =A0 out_8(®s->set_time, 0x1);
> + =A0 =A0 =A0 out_8(®s->set_time, 0x0);
> +}
> +
> +static int mpc5121_rtc_read_time(struct device *dev, struct rtc_time *tm=
)
> +{
> + =A0 =A0 =A0 struct mpc5121_rtc_data *rtc =3D dev_get_drvdata(dev);
> + =A0 =A0 =A0 struct mpc5121_rtc_regs __iomem *regs =3D rtc->regs;
> + =A0 =A0 =A0 unsigned long now;
> +
> + =A0 =A0 =A0 /*
> + =A0 =A0 =A0 =A0* linux time is actual_time plus the offset saved in tar=
get_time
> + =A0 =A0 =A0 =A0*/
> + =A0 =A0 =A0 now =3D in_be32(®s->actual_time) + in_be32(®s->target=
_time);
> +
> + =A0 =A0 =A0 rtc_time_to_tm(now, tm);
> +
> + =A0 =A0 =A0 /*
> + =A0 =A0 =A0 =A0* update second minute hour registers
> + =A0 =A0 =A0 =A0* so alarms will work
> + =A0 =A0 =A0 =A0*/
> + =A0 =A0 =A0 mpc5121_rtc_update_smh(regs, tm);
> +
> + =A0 =A0 =A0 return rtc_valid_tm(tm);
> +}
> +
> +static int mpc5121_rtc_set_time(struct device *dev, struct rtc_time *tm)
> +{
> + =A0 =A0 =A0 struct mpc5121_rtc_data *rtc =3D dev_get_drvdata(dev);
> + =A0 =A0 =A0 struct mpc5121_rtc_regs __iomem *regs =3D rtc->regs;
> + =A0 =A0 =A0 int ret;
> + =A0 =A0 =A0 unsigned long now;
> +
> + =A0 =A0 =A0 /*
> + =A0 =A0 =A0 =A0* The actual_time register is read only so we write the =
offset
> + =A0 =A0 =A0 =A0* between it and linux time to the target_time register.
> + =A0 =A0 =A0 =A0*/
> + =A0 =A0 =A0 ret =3D rtc_tm_to_time(tm, &now);
> + =A0 =A0 =A0 if (ret =3D=3D 0)
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 out_be32(®s->target_time, now - in_be32(=
®s->actual_time));
> +
> + =A0 =A0 =A0 /*
> + =A0 =A0 =A0 =A0* update second minute hour registers
> + =A0 =A0 =A0 =A0* so alarms will work
> + =A0 =A0 =A0 =A0*/
> + =A0 =A0 =A0 mpc5121_rtc_update_smh(regs, tm);
> +
> + =A0 =A0 =A0 return 0;
> +}
> +
> +static int mpc5121_rtc_read_alarm(struct device *dev, struct rtc_wkalrm =
*alarm)
> +{
> + =A0 =A0 =A0 struct mpc5121_rtc_data *rtc =3D dev_get_drvdata(dev);
> + =A0 =A0 =A0 struct mpc5121_rtc_regs __iomem *regs =3D rtc->regs;
> +
> + =A0 =A0 =A0 *alarm =3D rtc->wkalarm;
> +
> + =A0 =A0 =A0 alarm->pending =3D in_8(®s->alm_status);
> +
> + =A0 =A0 =A0 return 0;
> +}
> +
> +static int mpc5121_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *=
alarm)
> +{
> + =A0 =A0 =A0 struct mpc5121_rtc_data *rtc =3D dev_get_drvdata(dev);
> + =A0 =A0 =A0 struct mpc5121_rtc_regs __iomem *regs =3D rtc->regs;
> +
> + =A0 =A0 =A0 /*
> + =A0 =A0 =A0 =A0* the alarm has no seconds so deal with it
> + =A0 =A0 =A0 =A0*/
> + =A0 =A0 =A0 if (alarm->time.tm_sec) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 alarm->time.tm_sec =3D 0;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 alarm->time.tm_min++;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (alarm->time.tm_min >=3D 60) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 alarm->time.tm_min =3D 0;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 alarm->time.tm_hour++;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (alarm->time.tm_hour >=
=3D 24)
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 alarm->time=
.tm_hour =3D 0;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 }
> + =A0 =A0 =A0 }
> +
> + =A0 =A0 =A0 alarm->time.tm_mday =3D -1;
> + =A0 =A0 =A0 alarm->time.tm_mon =3D -1;
> + =A0 =A0 =A0 alarm->time.tm_year =3D -1;
> +
> + =A0 =A0 =A0 out_8(®s->alm_min_set, alarm->time.tm_min);
> + =A0 =A0 =A0 out_8(®s->alm_hour_set, alarm->time.tm_hour);
> +
> + =A0 =A0 =A0 out_8(®s->alm_enable, alarm->enabled);
> +
> + =A0 =A0 =A0 rtc->wkalarm =3D *alarm;
> + =A0 =A0 =A0 return 0;
> +}
> +
> +static irqreturn_t mpc5121_rtc_handler(int irq, void *dev)
> +{
> + =A0 =A0 =A0 struct mpc5121_rtc_data *rtc =3D dev_get_drvdata((struct de=
vice *)dev);
> + =A0 =A0 =A0 struct mpc5121_rtc_regs __iomem *regs =3D rtc->regs;
> +
> + =A0 =A0 =A0 if (in_8(®s->int_alm)) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 /* acknowledge and clear status */
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 out_8(®s->int_alm, 1);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 out_8(®s->alm_status, 1);
> +
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 rtc_update_irq(rtc->rtc, 1, RTC_IRQF | RTC_=
AF);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 return IRQ_HANDLED;
> + =A0 =A0 =A0 }
> +
> + =A0 =A0 =A0 return IRQ_NONE;
> +}
> +
> +static irqreturn_t mpc5121_rtc_handler_upd(int irq, void *dev)
> +{
> + =A0 =A0 =A0 struct mpc5121_rtc_data *rtc =3D dev_get_drvdata((struct de=
vice *)dev);
> + =A0 =A0 =A0 struct mpc5121_rtc_regs __iomem *regs =3D rtc->regs;
> +
> + =A0 =A0 =A0 if (in_8(®s->int_sec) && (in_8(®s->int_enable) & 0x1)=
) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 /* acknowledge */
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 out_8(®s->int_sec, 1);
> +
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 rtc_update_irq(rtc->rtc, 1, RTC_IRQF | RTC_=
UF);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 return IRQ_HANDLED;
> + =A0 =A0 =A0 }
> +
> + =A0 =A0 =A0 return IRQ_NONE;
> +}
> +
> +static int mpc5121_rtc_alarm_irq_enable(struct device *dev,
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0=
=A0 unsigned int enabled)
> +{
> + =A0 =A0 =A0 struct mpc5121_rtc_data *rtc =3D dev_get_drvdata(dev);
> + =A0 =A0 =A0 struct mpc5121_rtc_regs __iomem *regs =3D rtc->regs;
> + =A0 =A0 =A0 int val;
> +
> + =A0 =A0 =A0 if (enabled)
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 val =3D 1;
> + =A0 =A0 =A0 else
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 val =3D 0;
> +
> + =A0 =A0 =A0 out_8(®s->alm_enable, val);
> + =A0 =A0 =A0 rtc->wkalarm.enabled =3D val;
> +
> + =A0 =A0 =A0 return 0;
> +}
> +
> +static int mpc5121_rtc_update_irq_enable(struct device *dev,
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0=
=A0 =A0unsigned int enabled)
> +{
> + =A0 =A0 =A0 struct mpc5121_rtc_data *rtc =3D dev_get_drvdata(dev);
> + =A0 =A0 =A0 struct mpc5121_rtc_regs __iomem *regs =3D rtc->regs;
> + =A0 =A0 =A0 int val;
> +
> + =A0 =A0 =A0 val =3D in_8(®s->int_enable);
> +
> + =A0 =A0 =A0 if (enabled)
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 val =3D (val & ~0x8) | 0x1;
> + =A0 =A0 =A0 else
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 val &=3D ~0x1;
> +
> + =A0 =A0 =A0 out_8(®s->int_enable, val);
> +
> + =A0 =A0 =A0 return 0;
> +}
> +
> +static const struct rtc_class_ops mpc5121_rtc_ops =3D {
> + =A0 =A0 =A0 .read_time =3D mpc5121_rtc_read_time,
> + =A0 =A0 =A0 .set_time =3D mpc5121_rtc_set_time,
> + =A0 =A0 =A0 .read_alarm =3D mpc5121_rtc_read_alarm,
> + =A0 =A0 =A0 .set_alarm =3D mpc5121_rtc_set_alarm,
> + =A0 =A0 =A0 .alarm_irq_enable =3D mpc5121_rtc_alarm_irq_enable,
> + =A0 =A0 =A0 .update_irq_enable =3D mpc5121_rtc_update_irq_enable,
> +};
> +
> +static int __devinit mpc5121_rtc_probe(struct of_device *op,
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0=
=A0 const struct of_device_id *match)
> +{
> + =A0 =A0 =A0 struct mpc5121_rtc_data *rtc;
> + =A0 =A0 =A0 int err =3D 0;
> + =A0 =A0 =A0 u32 ka;
> +
> + =A0 =A0 =A0 rtc =3D kzalloc(sizeof(*rtc), GFP_KERNEL);
> + =A0 =A0 =A0 if (!rtc)
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 return -ENOMEM;
> +
> + =A0 =A0 =A0 rtc->regs =3D of_iomap(op->node, 0);
> + =A0 =A0 =A0 if (!rtc->regs) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 dev_err(&op->dev, "%s: couldn't map io spac=
e\n", __func__);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 err =3D -ENOSYS;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 goto out_free;
> + =A0 =A0 =A0 }
> +
> + =A0 =A0 =A0 device_init_wakeup(&op->dev, 1);
> +
> + =A0 =A0 =A0 dev_set_drvdata(&op->dev, rtc);
> +
> + =A0 =A0 =A0 rtc->irq =3D irq_of_parse_and_map(op->node, 1);
> + =A0 =A0 =A0 err =3D request_irq(rtc->irq, mpc5121_rtc_handler, IRQF_DIS=
ABLED,
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0=
=A0 =A0 =A0 =A0 =A0 "mpc5121-rtc", &op->dev);
> + =A0 =A0 =A0 if (err) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 dev_err(&op->dev, "%s: could not request ir=
q: %i\n",
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0=
=A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 __func__, rtc->irq);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 goto out_dispose;
> + =A0 =A0 =A0 }
> +
> + =A0 =A0 =A0 rtc->irq_periodic =3D irq_of_parse_and_map(op->node, 0);
> + =A0 =A0 =A0 err =3D request_irq(rtc->irq_periodic, mpc5121_rtc_handler_=
upd,
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 IRQF_DISABL=
ED, "mpc5121-rtc_upd", &op->dev);
> + =A0 =A0 =A0 if (err) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 dev_err(&op->dev, "%s: could not request ir=
q: %i\n",
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0=
=A0 =A0 =A0 =A0 =A0 __func__, rtc->irq_periodic);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 goto out_dispose2;
> + =A0 =A0 =A0 }
> +
> + =A0 =A0 =A0 ka =3D in_be32(&rtc->regs->keep_alive);
> + =A0 =A0 =A0 if (ka & 0x02) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 dev_warn(&op->dev,
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 "mpc5121-rtc: Battery or os=
cillator failure!\n");
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 out_be32(&rtc->regs->keep_alive, ka);
> + =A0 =A0 =A0 }
> +
> + =A0 =A0 =A0 rtc->rtc =3D rtc_device_register("mpc5121-rtc", &op->dev,
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0=
=A0 &mpc5121_rtc_ops, THIS_MODULE);
> + =A0 =A0 =A0 if (IS_ERR(rtc->rtc)) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 err =3D PTR_ERR(rtc->rtc);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 goto out_free_irq;
> + =A0 =A0 =A0 }
> +
> + =A0 =A0 =A0 return 0;
> +
> +out_free_irq:
> + =A0 =A0 =A0 free_irq(rtc->irq_periodic, &op->dev);
> +out_dispose2:
> + =A0 =A0 =A0 irq_dispose_mapping(rtc->irq_periodic);
> + =A0 =A0 =A0 free_irq(rtc->irq, &op->dev);
> +out_dispose:
> + =A0 =A0 =A0 irq_dispose_mapping(rtc->irq);
> + =A0 =A0 =A0 iounmap(rtc->regs);
> +out_free:
> + =A0 =A0 =A0 kfree(rtc);
> +
> + =A0 =A0 =A0 return err;
> +}
> +
> +static int __devexit mpc5121_rtc_remove(struct of_device *op)
> +{
> + =A0 =A0 =A0 struct mpc5121_rtc_data *rtc =3D dev_get_drvdata(&op->dev);
> + =A0 =A0 =A0 struct mpc5121_rtc_regs __iomem *regs =3D rtc->regs;
> +
> + =A0 =A0 =A0 /* disable interrupt, so there are no nasty surprises */
> + =A0 =A0 =A0 out_8(®s->alm_enable, 0);
> + =A0 =A0 =A0 out_8(®s->int_enable, in_8(®s->int_enable) & ~0x1);
> +
> + =A0 =A0 =A0 rtc_device_unregister(rtc->rtc);
> + =A0 =A0 =A0 iounmap(rtc->regs);
> + =A0 =A0 =A0 free_irq(rtc->irq, &op->dev);
> + =A0 =A0 =A0 free_irq(rtc->irq_periodic, &op->dev);
> + =A0 =A0 =A0 irq_dispose_mapping(rtc->irq);
> + =A0 =A0 =A0 irq_dispose_mapping(rtc->irq_periodic);
> + =A0 =A0 =A0 dev_set_drvdata(&op->dev, NULL);
> + =A0 =A0 =A0 kfree(rtc);
> +
> + =A0 =A0 =A0 return 0;
> +}
> +
> +static struct of_device_id mpc5121_rtc_match[] __devinitdata =3D {
> + =A0 =A0 =A0 { .compatible =3D "fsl,mpc5121-rtc", },
> + =A0 =A0 =A0 {},
> +};
> +
> +static struct of_platform_driver mpc5121_rtc_driver =3D {
> + =A0 =A0 =A0 .owner =3D THIS_MODULE,
> + =A0 =A0 =A0 .name =3D "mpc5121-rtc",
> + =A0 =A0 =A0 .match_table =3D mpc5121_rtc_match,
> + =A0 =A0 =A0 .probe =3D mpc5121_rtc_probe,
> + =A0 =A0 =A0 .remove =3D __devexit_p(mpc5121_rtc_remove),
> +};
> +
> +static int __init mpc5121_rtc_init(void)
> +{
> + =A0 =A0 =A0 return of_register_platform_driver(&mpc5121_rtc_driver);
> +}
> +module_init(mpc5121_rtc_init);
> +
> +static void __exit mpc5121_rtc_exit(void)
> +{
> + =A0 =A0 =A0 of_unregister_platform_driver(&mpc5121_rtc_driver);
> +}
> +module_exit(mpc5121_rtc_exit);
> +
> +MODULE_LICENSE("GPL");
> +MODULE_AUTHOR("John Rigby <jcrigby@gmail.com>");
> --
> 1.6.3.3
>
>
--=20
Grant Likely, B.Sc., P.Eng.
Secret Lab Technologies Ltd.
^ 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