* [net-next-2.6 PATCH v2 3/3] fs_enet: add FEC TX buffer alignment workaround for MPC5121
From: Anatolij Gustschin @ 2010-02-17 14:55 UTC (permalink / raw)
To: netdev
Cc: Wolfgang Denk, Detlev Zundel, linuxppc-dev, Anatolij Gustschin,
David S. Miller, Piotr Ziecik
In-Reply-To: <1266418530-2727-3-git-send-email-agust@denx.de>
MPC5121 FEC requeries 4-byte alignmnent for TX data buffers.
This patch is a work around that copies misaligned tx packets
to an aligned skb before sending.
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>
---
drivers/net/fs_enet/fs_enet-main.c | 44 ++++++++++++++++++++++++++++++++++++
1 files changed, 44 insertions(+), 0 deletions(-)
diff --git a/drivers/net/fs_enet/fs_enet-main.c b/drivers/net/fs_enet/fs_enet-main.c
index 4297021..166a89d 100644
--- a/drivers/net/fs_enet/fs_enet-main.c
+++ b/drivers/net/fs_enet/fs_enet-main.c
@@ -580,6 +580,37 @@ void fs_cleanup_bds(struct net_device *dev)
/**********************************************************************************/
+#ifdef CONFIG_FS_ENET_MPC5121_FEC
+/*
+ * MPC5121 FEC requeries 4-byte alignment for TX data buffer!
+ */
+static struct sk_buff *tx_skb_align_workaround(struct net_device *dev,
+ struct sk_buff *skb)
+{
+ struct sk_buff *new_skb;
+ struct fs_enet_private *fep = netdev_priv(dev);
+
+ /* Alloc new skb */
+ new_skb = dev_alloc_skb(ENET_RX_FRSIZE + 4);
+ if (!new_skb) {
+ dev_warn(fep->dev, "Memory squeeze, dropping tx packet.\n");
+ return NULL;
+ }
+
+ /* Make sure new skb is properly aligned */
+ skb_align(new_skb, 4);
+
+ /* Copy data to new skb ... */
+ skb_copy_from_linear_data(skb, new_skb->data, skb->len);
+ skb_put(new_skb, skb->len);
+
+ /* ... and free an old one */
+ dev_kfree_skb_any(skb);
+
+ return new_skb;
+}
+#endif
+
static int fs_enet_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
struct fs_enet_private *fep = netdev_priv(dev);
@@ -588,6 +619,19 @@ static int fs_enet_start_xmit(struct sk_buff *skb, struct net_device *dev)
u16 sc;
unsigned long flags;
+#ifdef CONFIG_FS_ENET_MPC5121_FEC
+ if (((unsigned long)skb->data) & 0x3) {
+ skb = tx_skb_align_workaround(dev, skb);
+ if (!skb) {
+ /*
+ * We have lost packet due to memory allocation error
+ * in tx_skb_align_workaround(). Hopefully original
+ * skb is still valid, so try transmit it later.
+ */
+ return NETDEV_TX_BUSY;
+ }
+ }
+#endif
spin_lock_irqsave(&fep->tx_lock, flags);
/*
--
1.6.3.3
^ permalink raw reply related
* Re: [net-next-2.6 PATCH v2 2/3] fs_enet: Add support for MPC512x to fs_enet driver
From: Grant Likely @ 2010-02-17 15:11 UTC (permalink / raw)
To: Anatolij Gustschin
Cc: Wolfgang Denk, Detlev Zundel, netdev, linuxppc-dev,
David S. Miller, Piotr Ziecik
In-Reply-To: <1266418530-2727-3-git-send-email-agust@denx.de>
On Wed, Feb 17, 2010 at 7:55 AM, Anatolij Gustschin <agust@denx.de> wrote:
> Extend the fs_enet driver to support MPC512x FEC.
> Enable it with CONFIG_FS_ENET_MPC5121_FEC option.
>
> 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>
Looks sane to me.
Acked-by: Grant Likely <grant.likely@secretlab.ca>
> ---
> =A0drivers/net/fs_enet/Kconfig =A0 =A0 =A0 =A0| =A0 10 +++++--
> =A0drivers/net/fs_enet/fs_enet-main.c | =A0 =A07 +++++
> =A0drivers/net/fs_enet/fs_enet.h =A0 =A0 =A0| =A0 49 ++++++++++++++++++++=
+++++++++++++++-
> =A0drivers/net/fs_enet/mac-fec.c =A0 =A0 =A0| =A0 46 ++++++++++++++++++++=
++-----------
> =A0drivers/net/fs_enet/mii-fec.c =A0 =A0 =A0| =A0 =A04 +-
> =A05 files changed, 95 insertions(+), 21 deletions(-)
>
> diff --git a/drivers/net/fs_enet/Kconfig b/drivers/net/fs_enet/Kconfig
> index 562ea68..fc073b5 100644
> --- a/drivers/net/fs_enet/Kconfig
> +++ b/drivers/net/fs_enet/Kconfig
> @@ -1,9 +1,13 @@
> =A0config FS_ENET
> =A0 =A0 =A0 =A0tristate "Freescale Ethernet Driver"
> - =A0 =A0 =A0 depends on CPM1 || CPM2
> + =A0 =A0 =A0 depends on CPM1 || CPM2 || PPC_MPC512x
> =A0 =A0 =A0 =A0select MII
> =A0 =A0 =A0 =A0select PHYLIB
>
> +config FS_ENET_MPC5121_FEC
> + =A0 =A0 =A0 def_bool y if (FS_ENET && PPC_MPC512x)
> + =A0 =A0 =A0 select FS_ENET_HAS_FEC
> +
> =A0config FS_ENET_HAS_SCC
> =A0 =A0 =A0 =A0bool "Chip has an SCC usable for ethernet"
> =A0 =A0 =A0 =A0depends on FS_ENET && (CPM1 || CPM2)
> @@ -16,13 +20,13 @@ config FS_ENET_HAS_FCC
>
> =A0config FS_ENET_HAS_FEC
> =A0 =A0 =A0 =A0bool "Chip has an FEC usable for ethernet"
> - =A0 =A0 =A0 depends on FS_ENET && CPM1
> + =A0 =A0 =A0 depends on FS_ENET && (CPM1 || FS_ENET_MPC5121_FEC)
> =A0 =A0 =A0 =A0select FS_ENET_MDIO_FEC
> =A0 =A0 =A0 =A0default y
>
> =A0config FS_ENET_MDIO_FEC
> =A0 =A0 =A0 =A0tristate "MDIO driver for FEC"
> - =A0 =A0 =A0 depends on FS_ENET && CPM1
> + =A0 =A0 =A0 depends on FS_ENET && (CPM1 || FS_ENET_MPC5121_FEC)
>
> =A0config FS_ENET_MDIO_FCC
> =A0 =A0 =A0 =A0tristate "MDIO driver for FCC"
> diff --git a/drivers/net/fs_enet/fs_enet-main.c b/drivers/net/fs_enet/fs_=
enet-main.c
> index c34a7e0..4297021 100644
> --- a/drivers/net/fs_enet/fs_enet-main.c
> +++ b/drivers/net/fs_enet/fs_enet-main.c
> @@ -1094,11 +1094,18 @@ static struct of_device_id fs_enet_match[] =3D {
> =A0 =A0 =A0 =A0},
> =A0#endif
> =A0#ifdef CONFIG_FS_ENET_HAS_FEC
> +#ifdef CONFIG_FS_ENET_MPC5121_FEC
> + =A0 =A0 =A0 {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 .compatible =3D "fsl,mpc5121-fec",
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 .data =3D (void *)&fs_fec_ops,
> + =A0 =A0 =A0 },
> +#else
> =A0 =A0 =A0 =A0{
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0.compatible =3D "fsl,pq1-fec-enet",
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0.data =3D (void *)&fs_fec_ops,
> =A0 =A0 =A0 =A0},
> =A0#endif
> +#endif
> =A0 =A0 =A0 =A0{}
> =A0};
> =A0MODULE_DEVICE_TABLE(of, fs_enet_match);
> diff --git a/drivers/net/fs_enet/fs_enet.h b/drivers/net/fs_enet/fs_enet.=
h
> index ef01e09..1ece4b1 100644
> --- a/drivers/net/fs_enet/fs_enet.h
> +++ b/drivers/net/fs_enet/fs_enet.h
> @@ -13,9 +13,56 @@
>
> =A0#ifdef CONFIG_CPM1
> =A0#include <asm/cpm1.h>
> +#endif
> +
> +#if defined(CONFIG_FS_ENET_HAS_FEC)
> +#include <asm/cpm.h>
> +
> +#if defined(CONFIG_FS_ENET_MPC5121_FEC)
> +/* MPC5121 FEC has different register layout */
> +struct fec {
> + =A0 =A0 =A0 u32 fec_reserved0;
> + =A0 =A0 =A0 u32 fec_ievent; =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 /* Interrup=
t event reg */
> + =A0 =A0 =A0 u32 fec_imask; =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0/* Interr=
upt mask reg */
> + =A0 =A0 =A0 u32 fec_reserved1;
> + =A0 =A0 =A0 u32 fec_r_des_active; =A0 =A0 =A0 =A0 =A0 /* Receive descri=
ptor reg */
> + =A0 =A0 =A0 u32 fec_x_des_active; =A0 =A0 =A0 =A0 =A0 /* Transmit descr=
iptor reg */
> + =A0 =A0 =A0 u32 fec_reserved2[3];
> + =A0 =A0 =A0 u32 fec_ecntrl; =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 /* Ethernet=
control reg */
> + =A0 =A0 =A0 u32 fec_reserved3[6];
> + =A0 =A0 =A0 u32 fec_mii_data; =A0 =A0 =A0 =A0 =A0 =A0 =A0 /* MII manage=
frame reg */
> + =A0 =A0 =A0 u32 fec_mii_speed; =A0 =A0 =A0 =A0 =A0 =A0 =A0/* MII speed =
control reg */
> + =A0 =A0 =A0 u32 fec_reserved4[7];
> + =A0 =A0 =A0 u32 fec_mib_ctrlstat; =A0 =A0 =A0 =A0 =A0 /* MIB control/st=
atus reg */
> + =A0 =A0 =A0 u32 fec_reserved5[7];
> + =A0 =A0 =A0 u32 fec_r_cntrl; =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0/* Receive =
control reg */
> + =A0 =A0 =A0 u32 fec_reserved6[15];
> + =A0 =A0 =A0 u32 fec_x_cntrl; =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0/* Transmit=
Control reg */
> + =A0 =A0 =A0 u32 fec_reserved7[7];
> + =A0 =A0 =A0 u32 fec_addr_low; =A0 =A0 =A0 =A0 =A0 =A0 =A0 /* Low 32bits=
MAC address */
> + =A0 =A0 =A0 u32 fec_addr_high; =A0 =A0 =A0 =A0 =A0 =A0 =A0/* High 16bit=
s MAC address */
> + =A0 =A0 =A0 u32 fec_opd; =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0/* Opco=
de + Pause duration */
> + =A0 =A0 =A0 u32 fec_reserved8[10];
> + =A0 =A0 =A0 u32 fec_hash_table_high; =A0 =A0 =A0 =A0/* High 32bits hash=
table */
> + =A0 =A0 =A0 u32 fec_hash_table_low; =A0 =A0 =A0 =A0 /* Low 32bits hash =
table */
> + =A0 =A0 =A0 u32 fec_grp_hash_table_high; =A0 =A0/* High 32bits hash tab=
le */
> + =A0 =A0 =A0 u32 fec_grp_hash_table_low; =A0 =A0 /* Low 32bits hash tabl=
e */
> + =A0 =A0 =A0 u32 fec_reserved9[7];
> + =A0 =A0 =A0 u32 fec_x_wmrk; =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 /* FIFO tra=
nsmit water mark */
> + =A0 =A0 =A0 u32 fec_reserved10;
> + =A0 =A0 =A0 u32 fec_r_bound; =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0/* FIFO rec=
eive bound reg */
> + =A0 =A0 =A0 u32 fec_r_fstart; =A0 =A0 =A0 =A0 =A0 =A0 =A0 /* FIFO recei=
ve start reg */
> + =A0 =A0 =A0 u32 fec_reserved11[11];
> + =A0 =A0 =A0 u32 fec_r_des_start; =A0 =A0 =A0 =A0 =A0 =A0/* Receive desc=
riptor ring */
> + =A0 =A0 =A0 u32 fec_x_des_start; =A0 =A0 =A0 =A0 =A0 =A0/* Transmit des=
criptor ring */
> + =A0 =A0 =A0 u32 fec_r_buff_size; =A0 =A0 =A0 =A0 =A0 =A0/* Maximum rece=
ive buff size */
> + =A0 =A0 =A0 u32 fec_reserved12[26];
> + =A0 =A0 =A0 u32 fec_dma_control; =A0 =A0 =A0 =A0 =A0 =A0/* DMA Endian a=
nd other ctrl */
> +};
> +#endif
>
> =A0struct fec_info {
> - =A0 =A0 =A0 fec_t __iomem *fecp;
> + =A0 =A0 =A0 struct fec __iomem *fecp;
> =A0 =A0 =A0 =A0u32 mii_speed;
> =A0};
> =A0#endif
> diff --git a/drivers/net/fs_enet/mac-fec.c b/drivers/net/fs_enet/mac-fec.=
c
> index 7047813..c9657da 100644
> --- a/drivers/net/fs_enet/mac-fec.c
> +++ b/drivers/net/fs_enet/mac-fec.c
> @@ -80,7 +80,7 @@
> =A0*/
> =A0#define FEC_RESET_DELAY =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A050
>
> -static int whack_reset(fec_t __iomem *fecp)
> +static int whack_reset(struct fec __iomem *fecp)
> =A0{
> =A0 =A0 =A0 =A0int i;
>
> @@ -168,7 +168,7 @@ static void cleanup_data(struct net_device *dev)
> =A0static void set_promiscuous_mode(struct net_device *dev)
> =A0{
> =A0 =A0 =A0 =A0struct fs_enet_private *fep =3D netdev_priv(dev);
> - =A0 =A0 =A0 fec_t __iomem *fecp =3D fep->fec.fecp;
> + =A0 =A0 =A0 struct fec __iomem *fecp =3D fep->fec.fecp;
>
> =A0 =A0 =A0 =A0FS(fecp, r_cntrl, FEC_RCNTRL_PROM);
> =A0}
> @@ -216,7 +216,7 @@ static void set_multicast_one(struct net_device *dev,=
const u8 *mac)
> =A0static void set_multicast_finish(struct net_device *dev)
> =A0{
> =A0 =A0 =A0 =A0struct fs_enet_private *fep =3D netdev_priv(dev);
> - =A0 =A0 =A0 fec_t __iomem *fecp =3D fep->fec.fecp;
> + =A0 =A0 =A0 struct fec __iomem *fecp =3D fep->fec.fecp;
>
> =A0 =A0 =A0 =A0/* if all multi or too many multicasts; just enable all */
> =A0 =A0 =A0 =A0if ((dev->flags & IFF_ALLMULTI) !=3D 0 ||
> @@ -246,7 +246,7 @@ static void set_multicast_list(struct net_device *dev=
)
> =A0static void restart(struct net_device *dev)
> =A0{
> =A0 =A0 =A0 =A0struct fs_enet_private *fep =3D netdev_priv(dev);
> - =A0 =A0 =A0 fec_t __iomem *fecp =3D fep->fec.fecp;
> + =A0 =A0 =A0 struct fec __iomem *fecp =3D fep->fec.fecp;
> =A0 =A0 =A0 =A0const struct fs_platform_info *fpi =3D fep->fpi;
> =A0 =A0 =A0 =A0dma_addr_t rx_bd_base_phys, tx_bd_base_phys;
> =A0 =A0 =A0 =A0int r;
> @@ -280,7 +280,11 @@ static void restart(struct net_device *dev)
> =A0 =A0 =A0 =A0 * Set maximum receive buffer size.
> =A0 =A0 =A0 =A0 */
> =A0 =A0 =A0 =A0FW(fecp, r_buff_size, PKT_MAXBLR_SIZE);
> +#ifdef CONFIG_FS_ENET_MPC5121_FEC
> + =A0 =A0 =A0 FW(fecp, r_cntrl, PKT_MAXBUF_SIZE << 16);
> +#else
> =A0 =A0 =A0 =A0FW(fecp, r_hash, PKT_MAXBUF_SIZE);
> +#endif
>
> =A0 =A0 =A0 =A0/* get physical address */
> =A0 =A0 =A0 =A0rx_bd_base_phys =3D fep->ring_mem_addr;
> @@ -297,7 +301,11 @@ static void restart(struct net_device *dev)
> =A0 =A0 =A0 =A0/*
> =A0 =A0 =A0 =A0 * Enable big endian and don't care about SDMA FC.
> =A0 =A0 =A0 =A0 */
> +#ifdef CONFIG_FS_ENET_MPC5121_FEC
> + =A0 =A0 =A0 FS(fecp, dma_control, 0xC0000000);
> +#else
> =A0 =A0 =A0 =A0FW(fecp, fun_code, 0x78000000);
> +#endif
>
> =A0 =A0 =A0 =A0/*
> =A0 =A0 =A0 =A0 * Set MII speed.
> @@ -308,9 +316,17 @@ static void restart(struct net_device *dev)
> =A0 =A0 =A0 =A0 * Clear any outstanding interrupt.
> =A0 =A0 =A0 =A0 */
> =A0 =A0 =A0 =A0FW(fecp, ievent, 0xffc0);
> +#ifndef CONFIG_FS_ENET_MPC5121_FEC
> =A0 =A0 =A0 =A0FW(fecp, ivec, (virq_to_hw(fep->interrupt) / 2) << 29);
>
> =A0 =A0 =A0 =A0FW(fecp, r_cntrl, FEC_RCNTRL_MII_MODE); /* MII enable */
> +#else
> + =A0 =A0 =A0 /*
> + =A0 =A0 =A0 =A0* Only set MII mode - do not touch maximum frame length
> + =A0 =A0 =A0 =A0* configured before.
> + =A0 =A0 =A0 =A0*/
> + =A0 =A0 =A0 FS(fecp, r_cntrl, FEC_RCNTRL_MII_MODE);
> +#endif
> =A0 =A0 =A0 =A0/*
> =A0 =A0 =A0 =A0 * adjust to duplex mode
> =A0 =A0 =A0 =A0 */
> @@ -339,7 +355,7 @@ static void stop(struct net_device *dev)
> =A0{
> =A0 =A0 =A0 =A0struct fs_enet_private *fep =3D netdev_priv(dev);
> =A0 =A0 =A0 =A0const struct fs_platform_info *fpi =3D fep->fpi;
> - =A0 =A0 =A0 fec_t __iomem *fecp =3D fep->fec.fecp;
> + =A0 =A0 =A0 struct fec __iomem *fecp =3D fep->fec.fecp;
>
> =A0 =A0 =A0 =A0struct fec_info* feci=3D fep->phydev->bus->priv;
>
> @@ -375,7 +391,7 @@ static void stop(struct net_device *dev)
> =A0static void napi_clear_rx_event(struct net_device *dev)
> =A0{
> =A0 =A0 =A0 =A0struct fs_enet_private *fep =3D netdev_priv(dev);
> - =A0 =A0 =A0 fec_t __iomem *fecp =3D fep->fec.fecp;
> + =A0 =A0 =A0 struct fec __iomem *fecp =3D fep->fec.fecp;
>
> =A0 =A0 =A0 =A0FW(fecp, ievent, FEC_NAPI_RX_EVENT_MSK);
> =A0}
> @@ -383,7 +399,7 @@ static void napi_clear_rx_event(struct net_device *de=
v)
> =A0static void napi_enable_rx(struct net_device *dev)
> =A0{
> =A0 =A0 =A0 =A0struct fs_enet_private *fep =3D netdev_priv(dev);
> - =A0 =A0 =A0 fec_t __iomem *fecp =3D fep->fec.fecp;
> + =A0 =A0 =A0 struct fec __iomem *fecp =3D fep->fec.fecp;
>
> =A0 =A0 =A0 =A0FS(fecp, imask, FEC_NAPI_RX_EVENT_MSK);
> =A0}
> @@ -391,7 +407,7 @@ static void napi_enable_rx(struct net_device *dev)
> =A0static void napi_disable_rx(struct net_device *dev)
> =A0{
> =A0 =A0 =A0 =A0struct fs_enet_private *fep =3D netdev_priv(dev);
> - =A0 =A0 =A0 fec_t __iomem *fecp =3D fep->fec.fecp;
> + =A0 =A0 =A0 struct fec __iomem *fecp =3D fep->fec.fecp;
>
> =A0 =A0 =A0 =A0FC(fecp, imask, FEC_NAPI_RX_EVENT_MSK);
> =A0}
> @@ -399,7 +415,7 @@ static void napi_disable_rx(struct net_device *dev)
> =A0static void rx_bd_done(struct net_device *dev)
> =A0{
> =A0 =A0 =A0 =A0struct fs_enet_private *fep =3D netdev_priv(dev);
> - =A0 =A0 =A0 fec_t __iomem *fecp =3D fep->fec.fecp;
> + =A0 =A0 =A0 struct fec __iomem *fecp =3D fep->fec.fecp;
>
> =A0 =A0 =A0 =A0FW(fecp, r_des_active, 0x01000000);
> =A0}
> @@ -407,7 +423,7 @@ static void rx_bd_done(struct net_device *dev)
> =A0static void tx_kickstart(struct net_device *dev)
> =A0{
> =A0 =A0 =A0 =A0struct fs_enet_private *fep =3D netdev_priv(dev);
> - =A0 =A0 =A0 fec_t __iomem *fecp =3D fep->fec.fecp;
> + =A0 =A0 =A0 struct fec __iomem *fecp =3D fep->fec.fecp;
>
> =A0 =A0 =A0 =A0FW(fecp, x_des_active, 0x01000000);
> =A0}
> @@ -415,7 +431,7 @@ static void tx_kickstart(struct net_device *dev)
> =A0static u32 get_int_events(struct net_device *dev)
> =A0{
> =A0 =A0 =A0 =A0struct fs_enet_private *fep =3D netdev_priv(dev);
> - =A0 =A0 =A0 fec_t __iomem *fecp =3D fep->fec.fecp;
> + =A0 =A0 =A0 struct fec __iomem *fecp =3D fep->fec.fecp;
>
> =A0 =A0 =A0 =A0return FR(fecp, ievent) & FR(fecp, imask);
> =A0}
> @@ -423,7 +439,7 @@ static u32 get_int_events(struct net_device *dev)
> =A0static void clear_int_events(struct net_device *dev, u32 int_events)
> =A0{
> =A0 =A0 =A0 =A0struct fs_enet_private *fep =3D netdev_priv(dev);
> - =A0 =A0 =A0 fec_t __iomem *fecp =3D fep->fec.fecp;
> + =A0 =A0 =A0 struct fec __iomem *fecp =3D fep->fec.fecp;
>
> =A0 =A0 =A0 =A0FW(fecp, ievent, int_events);
> =A0}
> @@ -439,17 +455,17 @@ static int get_regs(struct net_device *dev, void *p=
, int *sizep)
> =A0{
> =A0 =A0 =A0 =A0struct fs_enet_private *fep =3D netdev_priv(dev);
>
> - =A0 =A0 =A0 if (*sizep < sizeof(fec_t))
> + =A0 =A0 =A0 if (*sizep < sizeof(struct fec))
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0return -EINVAL;
>
> - =A0 =A0 =A0 memcpy_fromio(p, fep->fec.fecp, sizeof(fec_t));
> + =A0 =A0 =A0 memcpy_fromio(p, fep->fec.fecp, sizeof(struct fec));
>
> =A0 =A0 =A0 =A0return 0;
> =A0}
>
> =A0static int get_regs_len(struct net_device *dev)
> =A0{
> - =A0 =A0 =A0 return sizeof(fec_t);
> + =A0 =A0 =A0 return sizeof(struct fec);
> =A0}
>
> =A0static void tx_restart(struct net_device *dev)
> diff --git a/drivers/net/fs_enet/mii-fec.c b/drivers/net/fs_enet/mii-fec.=
c
> index 96eba42..5944b65 100644
> --- a/drivers/net/fs_enet/mii-fec.c
> +++ b/drivers/net/fs_enet/mii-fec.c
> @@ -52,7 +52,7 @@
> =A0static int fs_enet_fec_mii_read(struct mii_bus *bus , int phy_id, int =
location)
> =A0{
> =A0 =A0 =A0 =A0struct fec_info* fec =3D bus->priv;
> - =A0 =A0 =A0 fec_t __iomem *fecp =3D fec->fecp;
> + =A0 =A0 =A0 struct fec __iomem *fecp =3D fec->fecp;
> =A0 =A0 =A0 =A0int i, ret =3D -1;
>
> =A0 =A0 =A0 =A0BUG_ON((in_be32(&fecp->fec_r_cntrl) & FEC_RCNTRL_MII_MODE)=
=3D=3D 0);
> @@ -75,7 +75,7 @@ static int fs_enet_fec_mii_read(struct mii_bus *bus , i=
nt phy_id, int location)
> =A0static int fs_enet_fec_mii_write(struct mii_bus *bus, int phy_id, int =
location, u16 val)
> =A0{
> =A0 =A0 =A0 =A0struct fec_info* fec =3D bus->priv;
> - =A0 =A0 =A0 fec_t __iomem *fecp =3D fec->fecp;
> + =A0 =A0 =A0 struct fec __iomem *fecp =3D fec->fecp;
> =A0 =A0 =A0 =A0int i;
>
> =A0 =A0 =A0 =A0/* this must never happen */
> --
> 1.6.3.3
>
>
--=20
Grant Likely, B.Sc., P.Eng.
Secret Lab Technologies Ltd.
^ permalink raw reply
* Re: [net-next-2.6 PATCH v2 3/3] fs_enet: add FEC TX buffer alignment workaround for MPC5121
From: Grant Likely @ 2010-02-17 15:13 UTC (permalink / raw)
To: Anatolij Gustschin
Cc: Wolfgang Denk, Detlev Zundel, netdev, linuxppc-dev,
David S. Miller, Piotr Ziecik
In-Reply-To: <1266418530-2727-4-git-send-email-agust@denx.de>
On Wed, Feb 17, 2010 at 7:55 AM, Anatolij Gustschin <agust@denx.de> wrote:
> MPC5121 FEC requeries 4-byte alignmnent for TX data buffers.
> This patch is a work around that copies misaligned tx packets
> to an aligned skb before sending.
>
> 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>
Acked-by: Grant Likely <grant.likely@secretlab.ca>
> ---
> =A0drivers/net/fs_enet/fs_enet-main.c | =A0 44 ++++++++++++++++++++++++++=
++++++++++
> =A01 files changed, 44 insertions(+), 0 deletions(-)
>
> diff --git a/drivers/net/fs_enet/fs_enet-main.c b/drivers/net/fs_enet/fs_=
enet-main.c
> index 4297021..166a89d 100644
> --- a/drivers/net/fs_enet/fs_enet-main.c
> +++ b/drivers/net/fs_enet/fs_enet-main.c
> @@ -580,6 +580,37 @@ void fs_cleanup_bds(struct net_device *dev)
>
> =A0/*********************************************************************=
*************/
>
> +#ifdef CONFIG_FS_ENET_MPC5121_FEC
> +/*
> + * MPC5121 FEC requeries 4-byte alignment for TX data buffer!
> + */
> +static struct sk_buff *tx_skb_align_workaround(struct net_device *dev,
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0=
=A0 =A0 =A0 =A0 =A0struct sk_buff *skb)
> +{
> + =A0 =A0 =A0 struct sk_buff *new_skb;
> + =A0 =A0 =A0 struct fs_enet_private *fep =3D netdev_priv(dev);
> +
> + =A0 =A0 =A0 /* Alloc new skb */
> + =A0 =A0 =A0 new_skb =3D dev_alloc_skb(ENET_RX_FRSIZE + 4);
> + =A0 =A0 =A0 if (!new_skb) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 dev_warn(fep->dev, "Memory squeeze, droppin=
g tx packet.\n");
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 return NULL;
> + =A0 =A0 =A0 }
> +
> + =A0 =A0 =A0 /* Make sure new skb is properly aligned */
> + =A0 =A0 =A0 skb_align(new_skb, 4);
> +
> + =A0 =A0 =A0 /* Copy data to new skb ... */
> + =A0 =A0 =A0 skb_copy_from_linear_data(skb, new_skb->data, skb->len);
> + =A0 =A0 =A0 skb_put(new_skb, skb->len);
> +
> + =A0 =A0 =A0 /* ... and free an old one */
> + =A0 =A0 =A0 dev_kfree_skb_any(skb);
> +
> + =A0 =A0 =A0 return new_skb;
> +}
> +#endif
> +
> =A0static int fs_enet_start_xmit(struct sk_buff *skb, struct net_device *=
dev)
> =A0{
> =A0 =A0 =A0 =A0struct fs_enet_private *fep =3D netdev_priv(dev);
> @@ -588,6 +619,19 @@ static int fs_enet_start_xmit(struct sk_buff *skb, s=
truct net_device *dev)
> =A0 =A0 =A0 =A0u16 sc;
> =A0 =A0 =A0 =A0unsigned long flags;
>
> +#ifdef CONFIG_FS_ENET_MPC5121_FEC
> + =A0 =A0 =A0 if (((unsigned long)skb->data) & 0x3) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 skb =3D tx_skb_align_workaround(dev, skb);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (!skb) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 /*
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0* We have lost packet du=
e to memory allocation error
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0* in tx_skb_align_workar=
ound(). Hopefully original
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0* skb is still valid, so=
try transmit it later.
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0*/
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 return NETDEV_TX_BUSY;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 }
> + =A0 =A0 =A0 }
> +#endif
Instead of
> =A0 =A0 =A0 =A0spin_lock_irqsave(&fep->tx_lock, flags);
>
> =A0 =A0 =A0 =A0/*
> --
> 1.6.3.3
>
>
--=20
Grant Likely, B.Sc., P.Eng.
Secret Lab Technologies Ltd.
^ permalink raw reply
* Re: [net-next-2.6 PATCH v2 3/3] fs_enet: add FEC TX buffer alignment workaround for MPC5121
From: Eric Dumazet @ 2010-02-17 15:17 UTC (permalink / raw)
To: Anatolij Gustschin
Cc: Wolfgang Denk, Detlev Zundel, netdev, linuxppc-dev,
David S. Miller, Piotr Ziecik
In-Reply-To: <1266418530-2727-4-git-send-email-agust@denx.de>
Le mercredi 17 février 2010 à 15:55 +0100, Anatolij Gustschin a écrit :
> MPC5121 FEC requeries 4-byte alignmnent for TX data buffers.
> This patch is a work around that copies misaligned tx packets
> to an aligned skb before sending.
>
> 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>
> ---
> drivers/net/fs_enet/fs_enet-main.c | 44 ++++++++++++++++++++++++++++++++++++
> 1 files changed, 44 insertions(+), 0 deletions(-)
>
> diff --git a/drivers/net/fs_enet/fs_enet-main.c b/drivers/net/fs_enet/fs_enet-main.c
> index 4297021..166a89d 100644
> --- a/drivers/net/fs_enet/fs_enet-main.c
> +++ b/drivers/net/fs_enet/fs_enet-main.c
> @@ -580,6 +580,37 @@ void fs_cleanup_bds(struct net_device *dev)
>
> /**********************************************************************************/
>
> +#ifdef CONFIG_FS_ENET_MPC5121_FEC
> +/*
> + * MPC5121 FEC requeries 4-byte alignment for TX data buffer!
> + */
> +static struct sk_buff *tx_skb_align_workaround(struct net_device *dev,
> + struct sk_buff *skb)
> +{
> + struct sk_buff *new_skb;
> + struct fs_enet_private *fep = netdev_priv(dev);
> +
> + /* Alloc new skb */
> + new_skb = dev_alloc_skb(ENET_RX_FRSIZE + 4);
ENET_RX_FRSIZE looks strange in TX path
Why not using skb->len + 4 instead of ENET_RX_FRSIZE + 4 ?
> + if (!new_skb) {
> + dev_warn(fep->dev, "Memory squeeze, dropping tx packet.\n");
I am just wondering if this is ratelimited ?
> + return NULL;
> + }
> +
> + /* Make sure new skb is properly aligned */
> + skb_align(new_skb, 4);
> +
> + /* Copy data to new skb ... */
> + skb_copy_from_linear_data(skb, new_skb->data, skb->len);
> + skb_put(new_skb, skb->len);
> +
> + /* ... and free an old one */
> + dev_kfree_skb_any(skb);
> +
> + return new_skb;
> +}
> +#endif
> +
> static int fs_enet_start_xmit(struct sk_buff *skb, struct net_device *dev)
> {
> struct fs_enet_private *fep = netdev_priv(dev);
> @@ -588,6 +619,19 @@ static int fs_enet_start_xmit(struct sk_buff *skb, struct net_device *dev)
> u16 sc;
> unsigned long flags;
>
> +#ifdef CONFIG_FS_ENET_MPC5121_FEC
> + if (((unsigned long)skb->data) & 0x3) {
> + skb = tx_skb_align_workaround(dev, skb);
> + if (!skb) {
> + /*
> + * We have lost packet due to memory allocation error
> + * in tx_skb_align_workaround(). Hopefully original
> + * skb is still valid, so try transmit it later.
> + */
Could you define 'try to transmit later' ?
Who is responsible to trigger this event ?
> + return NETDEV_TX_BUSY;
> + }
> + }
> +#endif
> spin_lock_irqsave(&fep->tx_lock, flags);
>
> /*
^ permalink raw reply
* Re: Starting bare metal application on second core of P2020
From: Kumar Gala @ 2010-02-17 17:18 UTC (permalink / raw)
To: Felix Radensky; +Cc: linuxppc-dev
In-Reply-To: <4B7BE719.9070107@embedded-sol.com>
On Feb 17, 2010, at 6:54 AM, Felix Radensky wrote:
> Hi,
>=20
> We'd like to run Linux on core0 of P2020 and some bare metal =
application running without OS
> on core1. Is it possible to start this application from Linux ? I've =
seen example of running 2 copies
> of Linux in AMP mode, in which case both are started from u-boot. I'd =
like to leave core1 in
> reset, start Linux on core0 from u-boot and load bare metal =
application from Linux. If this
> possible, where can I learn about the procedure ?
There is no of the shelf support for this. It would be reasonable easy =
to create a driver to load up your application for Linux and kick the =
second cpu to start it.
- k=
^ permalink raw reply
* [Patch v2 1/2] 5200/mpc: improve i2c bus error recovery
From: Albrecht Dreß @ 2010-02-17 18:59 UTC (permalink / raw)
To: Linux PPC Development, Devicetree Discussions, Grant Likely,
Ben Dooks (embedded platforms)
Cc: Ira W. Snyder
This patch improves the recovery of the MPC's I2C bus from errors like bus
hangs resulting in timeouts:
1. make the bus timeout configurable, as it depends on the bus clock and
the attached slave chip(s); default is still 1 second;
2. detect any of the cases indicated by the CF, BB and RXAK MSR flags if a
timeout occurs, and add a missing (required) MAL reset;
3. use a more reliable method to fixup the bus if a hang has been detected.
The sequence is sent 9 times which seems to be necessary if a slave
"misses" more than one clock cycle. For 400 kHz bus speed, the fixup i=
s
also ~70us (81us vs. 150us) faster.
Tested on a custom Lite5200b derived board, with a Dallas RTC, AD sensors
and NXP IO expander chips attached to the i2c.
Changes vs. v1:
- use improved bus fixup sequence for all chips (not only the 5200)
- calculate real clock from defaults if no clock is given in the device tre=
e
- better description (I hope) of the changes.
I didn't split the changes in this file into three parts as recommended by
Grant, as they actually belong together (i.e. they address one single
problem, just in three places of one single source file).
Signed-off-by: Albrecht Dre=DF <albrecht.dress@arcor.de>
---
Note about the reset sequence: I verified the waveforms for 18.4kHz, 85.9kH=
z
and 375kHz (drop me a note if you want to see scope screen shots). Not
verified on other mpc chips yet.
@Ira: thanks in advance for giving it a try on your box!
--- linux-2.6.32-orig/drivers/i2c/busses/i2c-mpc.c 2009-12-03 04:51:21.0000=
00000 +0100
+++ linux-2.6.32/drivers/i2c/busses/i2c-mpc.c 2010-02-17 16:23:11.000000000=
+0100
@@ -59,6 +59,7 @@ struct mpc_i2c {
wait_queue_head_t queue;
struct i2c_adapter adap;
int irq;
+ u32 real_clk;
};
struct mpc_i2c_divider {
@@ -93,20 +94,23 @@ static irqreturn_t mpc_i2c_isr(int irq,
/* Sometimes 9th clock pulse isn't generated, and slave doesn't release
* the bus, because it wants to send ACK.
* Following sequence of enabling/disabling and sending start/stop genera=
tes
- * the pulse, so it's all OK.
+ * the 9 pulses, so it's all OK.
*/
static void mpc_i2c_fixup(struct mpc_i2c *i2c)
{
- writeccr(i2c, 0);
- udelay(30);
- writeccr(i2c, CCR_MEN);
- udelay(30);
- writeccr(i2c, CCR_MSTA | CCR_MTX);
- udelay(30);
- writeccr(i2c, CCR_MSTA | CCR_MTX | CCR_MEN);
- udelay(30);
- writeccr(i2c, CCR_MEN);
- udelay(30);
+ int k;
+ u32 delay_val =3D 1000000 / i2c->real_clk + 1;
+
+ if (delay_val < 2)
+ delay_val =3D 2;
+
+ for (k =3D 9; k; k--) {
+ writeccr(i2c, 0);
+ writeccr(i2c, CCR_MSTA | CCR_MTX | CCR_MEN);
+ udelay(delay_val);
+ writeccr(i2c, CCR_MEN);
+ udelay(delay_val << 1);
+ }
}
static int i2c_wait(struct mpc_i2c *i2c, unsigned timeout, int writing)
@@ -186,15 +190,19 @@ static const struct mpc_i2c_divider mpc_
{10240, 0x9d}, {12288, 0x9e}, {15360, 0x9f}
};
-int mpc_i2c_get_fdr_52xx(struct device_node *node, u32 clock, int prescale=
r)
+int mpc_i2c_get_fdr_52xx(struct device_node *node, u32 clock, int prescale=
r,
+ u32 *real_clk)
{
const struct mpc_i2c_divider *div =3D NULL;
unsigned int pvr =3D mfspr(SPRN_PVR);
u32 divider;
int i;
- if (!clock)
+ if (!clock) {
+ /* see below - default fdr =3D 0x3f -> div =3D 2048 */
+ *real_clk =3D mpc5xxx_get_bus_frequency(node) / 2048;
return -EINVAL;
+ }
/* Determine divider value */
divider =3D mpc5xxx_get_bus_frequency(node) / clock;
@@ -212,7 +220,8 @@ int mpc_i2c_get_fdr_52xx(struct device_n
break;
}
- return div ? (int)div->fdr : -EINVAL;
+ *real_clk =3D mpc5xxx_get_bus_frequency(node) / div->divider;
+ return (int)div->fdr;
}
static void mpc_i2c_setclock_52xx(struct device_node *node,
@@ -221,13 +230,14 @@ static void mpc_i2c_setclock_52xx(struct
{
int ret, fdr;
- ret =3D mpc_i2c_get_fdr_52xx(node, clock, prescaler);
+ ret =3D mpc_i2c_get_fdr_52xx(node, clock, prescaler, &i2c->real_clk);
fdr =3D (ret >=3D 0) ? ret : 0x3f; /* backward compatibility */
writeb(fdr & 0xff, i2c->base + MPC_I2C_FDR);
if (ret >=3D 0)
- dev_info(i2c->dev, "clock %d Hz (fdr=3D%d)\n", clock, fdr);
+ dev_info(i2c->dev, "clock %u Hz (fdr=3D%d)\n", i2c->real_clk,
+ fdr);
}
#else /* !CONFIG_PPC_MPC52xx */
static void mpc_i2c_setclock_52xx(struct device_node *node,
@@ -287,14 +297,18 @@ u32 mpc_i2c_get_sec_cfg_8xxx(void)
return val;
}
-int mpc_i2c_get_fdr_8xxx(struct device_node *node, u32 clock, u32 prescale=
r)
+int mpc_i2c_get_fdr_8xxx(struct device_node *node, u32 clock, u32 prescale=
r,
+ u32 *real_clk)
{
const struct mpc_i2c_divider *div =3D NULL;
u32 divider;
int i;
- if (!clock)
+ if (!clock) {
+ /* see below - default fdr =3D 0x1031 -> div =3D 16 * 3072 */
+ *real_clk =3D fsl_get_sys_freq() / prescaler / (16 * 3072);
return -EINVAL;
+ }
/* Determine proper divider value */
if (of_device_is_compatible(node, "fsl,mpc8544-i2c"))
@@ -317,6 +331,7 @@ int mpc_i2c_get_fdr_8xxx(struct device_n
break;
}
+ *real_clk =3D fsl_get_sys_freq() / prescaler / div->divider;
return div ? (int)div->fdr : -EINVAL;
}
@@ -326,7 +341,7 @@ static void mpc_i2c_setclock_8xxx(struct
{
int ret, fdr;
- ret =3D mpc_i2c_get_fdr_8xxx(node, clock, prescaler);
+ ret =3D mpc_i2c_get_fdr_8xxx(node, clock, prescaler, &i2c->real_clk);
fdr =3D (ret >=3D 0) ? ret : 0x1031; /* backward compatibility */
writeb(fdr & 0xff, i2c->base + MPC_I2C_FDR);
@@ -334,7 +349,7 @@ static void mpc_i2c_setclock_8xxx(struct
if (ret >=3D 0)
dev_info(i2c->dev, "clock %d Hz (dfsrr=3D%d fdr=3D%d)\n",
- clock, fdr >> 8, fdr & 0xff);
+ i2c->real_clk, fdr >> 8, fdr & 0xff);
}
#else /* !CONFIG_FSL_SOC */
@@ -446,10 +461,14 @@ static int mpc_xfer(struct i2c_adapter *
return -EINTR;
}
if (time_after(jiffies, orig_jiffies + HZ)) {
+ u8 status =3D readb(i2c->base + MPC_I2C_SR);
+
dev_dbg(i2c->dev, "timeout\n");
- if (readb(i2c->base + MPC_I2C_SR) =3D=3D
- (CSR_MCF | CSR_MBB | CSR_RXAK))
+ if ((status & (CSR_MCF | CSR_MBB | CSR_RXAK)) !=3D 0) {
+ writeb(status & ~CSR_MAL,
+ i2c->base + MPC_I2C_SR);
mpc_i2c_fixup(i2c);
+ }
return -EIO;
}
schedule();
@@ -540,6 +559,14 @@ static int __devinit fsl_i2c_probe(struc
}
}
+ prop =3D of_get_property(op->node, "fsl,timeout", &plen);
+ if (prop && plen =3D=3D sizeof(u32)) {
+ mpc_ops.timeout =3D *prop * HZ / 1000000;
+ if (mpc_ops.timeout < 5)
+ mpc_ops.timeout =3D 5;
+ }
+ dev_info(i2c->dev, "timeout %u us\n", mpc_ops.timeout * 1000000 / HZ);
+
dev_set_drvdata(&op->dev, i2c);
i2c->adap =3D mpc_ops;
^ permalink raw reply
* [Patch v2 2/2] 5200/mpc: improve i2c bus error recovery
From: Albrecht Dreß @ 2010-02-17 18:59 UTC (permalink / raw)
To: Linux PPC Development, Devicetree Discussions, Grant Likely,
Ben Dooks (embedded platforms)
Cc: Ira W. Snyder
Make the I2C adapter timeout configurable through a Device Tree property
which gives the timeout in microseconds.
Change vs. v.1: use "fsl,timeout" as property name (Thanks, Grant)
Signed-off-by: Albrecht Dre=DF <albrecht.dress@arcor.de>
---
--- linux-2.6.32-orig/Documentation/powerpc/dts-bindings/fsl/i2c.txt 2009-1=
2-03 04:51:21.000000000 +0100
+++ linux-2.6.32/Documentation/powerpc/dts-bindings/fsl/i2c.txt 2010-02-17 =
14:18:01.000000000 +0100
@@ -21,6 +21,7 @@ Recommended properties :
- 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.
+ - fsl,timeout : I2C bus timeout in microseconds.
Examples :
@@ -44,5 +45,6 @@ Examples :
interrupts =3D <43 2>;
interrupt-parent =3D <&mpic>;
clock-frequency =3D <400000>;
+ fsl,timeout =3D <10000>;
};
^ permalink raw reply
* Re: [Patch v2 1/2] 5200/mpc: improve i2c bus error recovery
From: Grant Likely @ 2010-02-17 20:10 UTC (permalink / raw)
To: Albrecht Dreß
Cc: Linux PPC Development, Devicetree Discussions,
Ben Dooks (embedded platforms), Ira W. Snyder
In-Reply-To: <1266433154.2322.0@antares>
On Wed, Feb 17, 2010 at 11:59 AM, Albrecht Dre=DF <albrecht.dress@arcor.de>=
wrote:
> This patch improves the recovery of the MPC's I2C bus from errors like bu=
s
> hangs resulting in timeouts:
> 1. make the bus timeout configurable, as it depends on the bus clock and
> =A0 the attached slave chip(s); default is still 1 second;
> 2. detect any of the cases indicated by the CF, BB and RXAK MSR flags if =
a
> =A0 timeout occurs, and add a missing (required) MAL reset;
> 3. use a more reliable method to fixup the bus if a hang has been detecte=
d.
> =A0 The sequence is sent 9 times which seems to be necessary if a slave
> =A0 "misses" more than one clock cycle. =A0For 400 kHz bus speed, the fix=
up is
> =A0 also ~70us (81us vs. 150us) faster.
>
> Tested on a custom Lite5200b derived board, with a Dallas RTC, AD sensors
> and NXP IO expander chips attached to the i2c.
>
> Changes vs. v1:
> - use improved bus fixup sequence for all chips (not only the 5200)
> - calculate real clock from defaults if no clock is given in the device t=
ree
> - better description (I hope) of the changes.
>
> I didn't split the changes in this file into three parts as recommended b=
y
> Grant, as they actually belong together (i.e. they address one single
> problem, just in three places of one single source file).
>
> Signed-off-by: Albrecht Dre=DF <albrecht.dress@arcor.de>
Acked-by: Grant Likely <grant.likely@secretlab.ca>
>
> ---
>
> Note about the reset sequence: I verified the waveforms for 18.4kHz, 85.9=
kHz
> and 375kHz (drop me a note if you want to see scope screen shots). =A0Not
> verified on other mpc chips yet.
> @Ira: thanks in advance for giving it a try on your box!
>
>
> --- linux-2.6.32-orig/drivers/i2c/busses/i2c-mpc.c =A0 =A0 =A02009-12-03
> 04:51:21.000000000 +0100
> +++ linux-2.6.32/drivers/i2c/busses/i2c-mpc.c =A0 2010-02-17
> 16:23:11.000000000 +0100
> @@ -59,6 +59,7 @@ struct mpc_i2c {
> =A0 =A0 =A0 =A0wait_queue_head_t queue;
> =A0 =A0 =A0 =A0struct i2c_adapter adap;
> =A0 =A0 =A0 =A0int irq;
> + =A0 =A0 =A0 u32 real_clk;
> =A0};
>
> =A0struct mpc_i2c_divider {
> @@ -93,20 +94,23 @@ static irqreturn_t mpc_i2c_isr(int irq,
> =A0/* Sometimes 9th clock pulse isn't generated, and slave doesn't releas=
e
> =A0* the bus, because it wants to send ACK.
> =A0* Following sequence of enabling/disabling and sending start/stop gene=
rates
> - * the pulse, so it's all OK.
> + * the 9 pulses, so it's all OK.
> =A0*/
> =A0static void mpc_i2c_fixup(struct mpc_i2c *i2c)
> =A0{
> - =A0 =A0 =A0 writeccr(i2c, 0);
> - =A0 =A0 =A0 udelay(30);
> - =A0 =A0 =A0 writeccr(i2c, CCR_MEN);
> - =A0 =A0 =A0 udelay(30);
> - =A0 =A0 =A0 writeccr(i2c, CCR_MSTA | CCR_MTX);
> - =A0 =A0 =A0 udelay(30);
> - =A0 =A0 =A0 writeccr(i2c, CCR_MSTA | CCR_MTX | CCR_MEN);
> - =A0 =A0 =A0 udelay(30);
> - =A0 =A0 =A0 writeccr(i2c, CCR_MEN);
> - =A0 =A0 =A0 udelay(30);
> + =A0 =A0 =A0 int k;
> + =A0 =A0 =A0 u32 delay_val =3D 1000000 / i2c->real_clk + 1;
> +
> + =A0 =A0 =A0 if (delay_val < 2)
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 delay_val =3D 2;
> +
> + =A0 =A0 =A0 for (k =3D 9; k; k--) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 writeccr(i2c, 0);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 writeccr(i2c, CCR_MSTA | CCR_MTX | CCR_MEN)=
;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 udelay(delay_val);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 writeccr(i2c, CCR_MEN);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 udelay(delay_val << 1);
> + =A0 =A0 =A0 }
> =A0}
>
> =A0static int i2c_wait(struct mpc_i2c *i2c, unsigned timeout, int writing=
)
> @@ -186,15 +190,19 @@ static const struct mpc_i2c_divider mpc_
> =A0 =A0 =A0 =A0{10240, 0x9d}, {12288, 0x9e}, {15360, 0x9f}
> =A0};
>
> -int mpc_i2c_get_fdr_52xx(struct device_node *node, u32 clock, int
> prescaler)
> +int mpc_i2c_get_fdr_52xx(struct device_node *node, u32 clock, int
> prescaler,
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0u32 *real_clk)
> =A0{
> =A0 =A0 =A0 =A0const struct mpc_i2c_divider *div =3D NULL;
> =A0 =A0 =A0 =A0unsigned int pvr =3D mfspr(SPRN_PVR);
> =A0 =A0 =A0 =A0u32 divider;
> =A0 =A0 =A0 =A0int i;
>
> - =A0 =A0 =A0 if (!clock)
> + =A0 =A0 =A0 if (!clock) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 /* see below - default fdr =3D 0x3f -> div =
=3D 2048 */
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 *real_clk =3D mpc5xxx_get_bus_frequency(nod=
e) / 2048;
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0return -EINVAL;
> + =A0 =A0 =A0 }
>
> =A0 =A0 =A0 =A0/* Determine divider value */
> =A0 =A0 =A0 =A0divider =3D mpc5xxx_get_bus_frequency(node) / clock;
> @@ -212,7 +220,8 @@ int mpc_i2c_get_fdr_52xx(struct device_n
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0break;
> =A0 =A0 =A0 =A0}
>
> - =A0 =A0 =A0 return div ? (int)div->fdr : -EINVAL;
> + =A0 =A0 =A0 *real_clk =3D mpc5xxx_get_bus_frequency(node) / div->divide=
r;
> + =A0 =A0 =A0 return (int)div->fdr;
> =A0}
>
> =A0static void mpc_i2c_setclock_52xx(struct device_node *node,
> @@ -221,13 +230,14 @@ static void mpc_i2c_setclock_52xx(struct
> =A0{
> =A0 =A0 =A0 =A0int ret, fdr;
>
> - =A0 =A0 =A0 ret =3D mpc_i2c_get_fdr_52xx(node, clock, prescaler);
> + =A0 =A0 =A0 ret =3D mpc_i2c_get_fdr_52xx(node, clock, prescaler, &i2c->=
real_clk);
> =A0 =A0 =A0 =A0fdr =3D (ret >=3D 0) ? ret : 0x3f; /* backward compatibili=
ty */
>
> =A0 =A0 =A0 =A0writeb(fdr & 0xff, i2c->base + MPC_I2C_FDR);
>
> =A0 =A0 =A0 =A0if (ret >=3D 0)
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 dev_info(i2c->dev, "clock %d Hz (fdr=3D%d)\=
n", clock, fdr);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 dev_info(i2c->dev, "clock %u Hz (fdr=3D%d)\=
n", i2c->real_clk,
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0fdr);
> =A0}
> =A0#else /* !CONFIG_PPC_MPC52xx */
> =A0static void mpc_i2c_setclock_52xx(struct device_node *node,
> @@ -287,14 +297,18 @@ u32 mpc_i2c_get_sec_cfg_8xxx(void)
> =A0 =A0 =A0 =A0return val;
> =A0}
>
> -int mpc_i2c_get_fdr_8xxx(struct device_node *node, u32 clock, u32
> prescaler)
> +int mpc_i2c_get_fdr_8xxx(struct device_node *node, u32 clock, u32
> prescaler,
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0u32 *real_clk)
> =A0{
> =A0 =A0 =A0 =A0const struct mpc_i2c_divider *div =3D NULL;
> =A0 =A0 =A0 =A0u32 divider;
> =A0 =A0 =A0 =A0int i;
>
> - =A0 =A0 =A0 if (!clock)
> + =A0 =A0 =A0 if (!clock) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 /* see below - default fdr =3D 0x1031 -> di=
v =3D 16 * 3072 */
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 *real_clk =3D fsl_get_sys_freq() / prescale=
r / (16 * 3072);
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0return -EINVAL;
> + =A0 =A0 =A0 }
>
> =A0 =A0 =A0 =A0/* Determine proper divider value */
> =A0 =A0 =A0 =A0if (of_device_is_compatible(node, "fsl,mpc8544-i2c"))
> @@ -317,6 +331,7 @@ int mpc_i2c_get_fdr_8xxx(struct device_n
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0break;
> =A0 =A0 =A0 =A0}
>
> + =A0 =A0 =A0 *real_clk =3D fsl_get_sys_freq() / prescaler / div->divider=
;
> =A0 =A0 =A0 =A0return div ? (int)div->fdr : -EINVAL;
> =A0}
>
> @@ -326,7 +341,7 @@ static void mpc_i2c_setclock_8xxx(struct
> =A0{
> =A0 =A0 =A0 =A0int ret, fdr;
>
> - =A0 =A0 =A0 ret =3D mpc_i2c_get_fdr_8xxx(node, clock, prescaler);
> + =A0 =A0 =A0 ret =3D mpc_i2c_get_fdr_8xxx(node, clock, prescaler, &i2c->=
real_clk);
> =A0 =A0 =A0 =A0fdr =3D (ret >=3D 0) ? ret : 0x1031; /* backward compatibi=
lity */
>
> =A0 =A0 =A0 =A0writeb(fdr & 0xff, i2c->base + MPC_I2C_FDR);
> @@ -334,7 +349,7 @@ static void mpc_i2c_setclock_8xxx(struct
>
> =A0 =A0 =A0 =A0if (ret >=3D 0)
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0dev_info(i2c->dev, "clock %d Hz (dfsrr=3D%=
d fdr=3D%d)\n",
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0clock, fdr >> 8, fdr & 0=
xff);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0i2c->real_clk, fdr >> 8,=
fdr & 0xff);
> =A0}
>
> =A0#else /* !CONFIG_FSL_SOC */
> @@ -446,10 +461,14 @@ static int mpc_xfer(struct i2c_adapter *
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0return -EINTR;
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0}
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0if (time_after(jiffies, orig_jiffies + HZ)=
) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 u8 status =3D readb(i2c->ba=
se + MPC_I2C_SR);
> +
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0dev_dbg(i2c->dev, "timeout=
\n");
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (readb(i2c->base + MPC_I=
2C_SR) =3D=3D
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 (CSR_MCF | CSR_MBB =
| CSR_RXAK))
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 if ((status & (CSR_MCF | CS=
R_MBB | CSR_RXAK)) !=3D 0)
> {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 writeb(stat=
us & ~CSR_MAL,
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0=
=A0i2c->base + MPC_I2C_SR);
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0mpc_i2c_fi=
xup(i2c);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 }
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0return -EIO;
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0}
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0schedule();
> @@ -540,6 +559,14 @@ static int __devinit fsl_i2c_probe(struc
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0}
> =A0 =A0 =A0 =A0}
>
> + =A0 =A0 =A0 prop =3D of_get_property(op->node, "fsl,timeout", &plen);
> + =A0 =A0 =A0 if (prop && plen =3D=3D sizeof(u32)) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 mpc_ops.timeout =3D *prop * HZ / 1000000;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (mpc_ops.timeout < 5)
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 mpc_ops.timeout =3D 5;
> + =A0 =A0 =A0 }
> + =A0 =A0 =A0 dev_info(i2c->dev, "timeout %u us\n", mpc_ops.timeout * 100=
0000 /
> HZ);
> +
> =A0 =A0 =A0 =A0dev_set_drvdata(&op->dev, i2c);
>
> =A0 =A0 =A0 =A0i2c->adap =3D mpc_ops;
>
--=20
Grant Likely, B.Sc., P.Eng.
Secret Lab Technologies Ltd.
^ permalink raw reply
* Re: [Patch v2 2/2] 5200/mpc: improve i2c bus error recovery
From: Grant Likely @ 2010-02-17 20:10 UTC (permalink / raw)
To: Albrecht Dreß
Cc: Linux PPC Development, Devicetree Discussions,
Ben Dooks (embedded platforms), Ira W. Snyder
In-Reply-To: <1266433158.2322.1@antares>
On Wed, Feb 17, 2010 at 11:59 AM, Albrecht Dre=DF <albrecht.dress@arcor.de>=
wrote:
> Make the I2C adapter timeout configurable through a Device Tree property
> which gives the timeout in microseconds.
>
> Change vs. v.1: use "fsl,timeout" as property name (Thanks, Grant)
>
> Signed-off-by: Albrecht Dre=DF <albrecht.dress@arcor.de>
Acked-by: Grant Likely <grant.likely@secretlab.ca>
>
> ---
>
> --- linux-2.6.32-orig/Documentation/powerpc/dts-bindings/fsl/i2c.txt
> =A02009-12-03 04:51:21.000000000 +0100
> +++ linux-2.6.32/Documentation/powerpc/dts-bindings/fsl/i2c.txt 2010-02-1=
7
> 14:18:01.000000000 +0100
> @@ -21,6 +21,7 @@ Recommended properties :
> =A0- fsl,preserve-clocking : boolean; if defined, the clock settings
> =A0 =A0from the bootloader are preserved (not touched).
> =A0- clock-frequency : desired I2C bus clock frequency in Hz.
> + - fsl,timeout : I2C bus timeout in microseconds.
>
> =A0Examples :
>
> @@ -44,5 +45,6 @@ Examples :
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0interrupts =3D <43 2>;
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0interrupt-parent =3D <&mpic>;
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0clock-frequency =3D <400000>;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 fsl,timeout =3D <10000>;
> =A0 =A0 =A0 =A0};
>
>
--=20
Grant Likely, B.Sc., P.Eng.
Secret Lab Technologies Ltd.
^ permalink raw reply
* [PATCH v4 0/5] PCI: try "pci=use_crs" again
From: Bjorn Helgaas @ 2010-02-17 20:19 UTC (permalink / raw)
To: Jesse Barnes
Cc: Matthew Garrett, Tony Luck, linuxppc-dev, linux-pci, Peter Haight,
Gary Hade, linux-kernel, linux-acpi, linux-am33-list,
Linus Torvalds, Ingo Molnar, Yinghai Lu, Larry Finger
Historically, Linux has assumed a single PCI host bridge, with that bridge
claiming all the address space left after RAM and legacy devices are taken out.
If the system contains multiple host bridges, we can no longer operate under
that assumption. We have to know what parts of the address space are claimed
by each bridge so that when we assign resources to a PCI device, we take them
from a range claimed by the upstream host bridge.
On x86 and ia64, we use ACPI to enumerate all the PCI host bridges in the
system, and part of the host bridge description is the "_CRS" (current resource
settings" property, which lists the address space used by the bridge. On x86,
we currently ignore most of the _CRS information. This patch series changes
this, so we will use _CRS to learn about the host bridge windows.
Since most x86 machines with multiple host bridges are relatively new, this
series only turns this on for machines with BIOS dates of 2008 or newer.
Changes from v3 to v4:
- Keep the bus->resource[] table to avoid having to change all arches
at once, but reduce it to size 4 (minimum required for P2P & CardBus
bridges).
- Store additional host bridge or subtractive decode windows in a list.
- Add pci_bus_for_each_resource() iterator to hide PCI_BUS_NUM_RESOURCES
and the table/list split. This reduces the size of the main patch.
- Remove tidy-up patches completely; they feel like distractions to this
series.
Changes from v2 to v3:
- Fix alpha, powerpc, and mn10300 references to pci_bus resource table
- Turn on "pci=use_crs" for 2008 and newer, not 2010 and newer
- Remove Toshiba A355 quirk (BIOS date is 2009, so automatically included)
- Remove IBM x3850 and x3950 quirks (BIOS dates in 2008, so automatically
included)
- Leave IBM x3800 quirk (pre-2008 BIOS)
- Use "bool" for pci_use_crs (new to me, but I see akpm suggesting it)
- Reorder so the important patches are first
Changes from v1 to v2:
- Rebase to be6e9f7853e
- Add patch to clean up "disabled window" printk
- Add bugzilla reference comment in use_crs DMI quirk
---
Bjorn Helgaas (5):
PCI: split up pci_read_bridge_bases()
PCI: read bridge windows before filling in subtractive decode resources
PCI: add pci_bus_for_each_resource(), remove direct bus->resource[] refs
PCI: augment bus resource table with a list
x86/PCI: use host bridge _CRS info by default on 2008 and newer machines
Documentation/kernel-parameters.txt | 8 ++-
arch/ia64/include/asm/acpi.h | 1
arch/ia64/pci/pci.c | 17 ++-----
arch/mn10300/unit-asb2305/pci.c | 6 +-
arch/powerpc/kernel/pci-common.c | 11 ++---
arch/powerpc/platforms/fsl_uli1575.c | 12 ++---
arch/x86/include/asm/pci_x86.h | 1
arch/x86/pci/acpi.c | 82 ++++++++++++++++++++--------------
arch/x86/pci/bus_numa.c | 3 +
arch/x86/pci/bus_numa.h | 3 -
arch/x86/pci/common.c | 3 +
drivers/acpi/pci_root.c | 1
drivers/pci/bus.c | 49 +++++++++++++++++++-
drivers/pci/hotplug/shpchp_sysfs.c | 9 +---
drivers/pci/pci.c | 5 +-
drivers/pci/probe.c | 68 ++++++++++++++++++++++------
drivers/pci/setup-bus.c | 10 ++--
drivers/pcmcia/rsrc_nonstatic.c | 3 -
drivers/pcmcia/yenta_socket.c | 5 +-
include/acpi/acpi_drivers.h | 1
include/linux/pci.h | 36 +++++++++++++--
21 files changed, 226 insertions(+), 108 deletions(-)
^ permalink raw reply
* [PATCH v4 1/5] PCI: split up pci_read_bridge_bases()
From: Bjorn Helgaas @ 2010-02-17 20:19 UTC (permalink / raw)
To: Jesse Barnes
Cc: Matthew Garrett, Tony Luck, linuxppc-dev, linux-pci, Peter Haight,
Gary Hade, linux-kernel, linux-acpi, linux-am33-list,
Linus Torvalds, Ingo Molnar, Yinghai Lu, Larry Finger
In-Reply-To: <20100217201654.4013.70201.stgit@bob.kio>
No functional change; this breaks up pci_read_bridge_bases() into separate
pieces for the I/O, memory, and prefetchable memory windows, similar to how
Yinghai recently split up pci_setup_bridge() in 68e84ff3bdc.
Signed-off-by: Bjorn Helgaas <bjorn.helgaas@hp.com>
---
drivers/pci/probe.c | 54 +++++++++++++++++++++++++++++++++++++--------------
1 files changed, 39 insertions(+), 15 deletions(-)
diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
index d300943..4b47b4b 100644
--- a/drivers/pci/probe.c
+++ b/drivers/pci/probe.c
@@ -281,26 +281,12 @@ static void pci_read_bases(struct pci_dev *dev, unsigned int howmany, int rom)
}
}
-void __devinit pci_read_bridge_bases(struct pci_bus *child)
+static void __devinit pci_read_bridge_io(struct pci_bus *child)
{
struct pci_dev *dev = child->self;
u8 io_base_lo, io_limit_lo;
- u16 mem_base_lo, mem_limit_lo;
unsigned long base, limit;
struct resource *res;
- int i;
-
- if (pci_is_root_bus(child)) /* It's a host bus, nothing to read */
- return;
-
- dev_info(&dev->dev, "PCI bridge to [bus %02x-%02x]%s\n",
- child->secondary, child->subordinate,
- dev->transparent ? " (subtractive decode)": "");
-
- if (dev->transparent) {
- for(i = 3; i < PCI_BUS_NUM_RESOURCES; i++)
- child->resource[i] = child->parent->resource[i - 3];
- }
res = child->resource[0];
pci_read_config_byte(dev, PCI_IO_BASE, &io_base_lo);
@@ -328,6 +314,14 @@ void __devinit pci_read_bridge_bases(struct pci_bus *child)
" bridge window [io %04lx - %04lx] reg reading\n",
base, limit);
}
+}
+
+static void __devinit pci_read_bridge_mmio(struct pci_bus *child)
+{
+ struct pci_dev *dev = child->self;
+ u16 mem_base_lo, mem_limit_lo;
+ unsigned long base, limit;
+ struct resource *res;
res = child->resource[1];
pci_read_config_word(dev, PCI_MEMORY_BASE, &mem_base_lo);
@@ -344,6 +338,14 @@ void __devinit pci_read_bridge_bases(struct pci_bus *child)
" bridge window [mem 0x%08lx - 0x%08lx] reg reading\n",
base, limit + 0xfffff);
}
+}
+
+static void __devinit pci_read_bridge_mmio_pref(struct pci_bus *child)
+{
+ struct pci_dev *dev = child->self;
+ u16 mem_base_lo, mem_limit_lo;
+ unsigned long base, limit;
+ struct resource *res;
res = child->resource[2];
pci_read_config_word(dev, PCI_PREF_MEMORY_BASE, &mem_base_lo);
@@ -389,6 +391,28 @@ void __devinit pci_read_bridge_bases(struct pci_bus *child)
}
}
+void __devinit pci_read_bridge_bases(struct pci_bus *child)
+{
+ struct pci_dev *dev = child->self;
+ int i;
+
+ if (pci_is_root_bus(child)) /* It's a host bus, nothing to read */
+ return;
+
+ dev_info(&dev->dev, "PCI bridge to [bus %02x-%02x]%s\n",
+ child->secondary, child->subordinate,
+ dev->transparent ? " (subtractive decode)" : "");
+
+ if (dev->transparent) {
+ for (i = 3; i < PCI_BUS_NUM_RESOURCES; i++)
+ child->resource[i] = child->parent->resource[i - 3];
+ }
+
+ pci_read_bridge_io(child);
+ pci_read_bridge_mmio(child);
+ pci_read_bridge_mmio_pref(child);
+}
+
static struct pci_bus * pci_alloc_bus(void)
{
struct pci_bus *b;
^ permalink raw reply related
* [PATCH v4 2/5] PCI: read bridge windows before filling in subtractive decode resources
From: Bjorn Helgaas @ 2010-02-17 20:19 UTC (permalink / raw)
To: Jesse Barnes
Cc: Matthew Garrett, Tony Luck, linuxppc-dev, linux-pci, Peter Haight,
Gary Hade, linux-kernel, linux-acpi, linux-am33-list,
Linus Torvalds, Ingo Molnar, Yinghai Lu, Larry Finger
In-Reply-To: <20100217201654.4013.70201.stgit@bob.kio>
No functional change; this fills in the bus subtractive decode resources
after reading the bridge window information rather than before. Also,
print out the subtractive decode resources as we already do for the
positive decode windows.
Signed-off-by: Bjorn Helgaas <bjorn.helgaas@hp.com>
---
drivers/pci/probe.c | 15 ++++++++++-----
1 files changed, 10 insertions(+), 5 deletions(-)
diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
index 4b47b4b..70c4ed2 100644
--- a/drivers/pci/probe.c
+++ b/drivers/pci/probe.c
@@ -403,14 +403,19 @@ void __devinit pci_read_bridge_bases(struct pci_bus *child)
child->secondary, child->subordinate,
dev->transparent ? " (subtractive decode)" : "");
- if (dev->transparent) {
- for (i = 3; i < PCI_BUS_NUM_RESOURCES; i++)
- child->resource[i] = child->parent->resource[i - 3];
- }
-
pci_read_bridge_io(child);
pci_read_bridge_mmio(child);
pci_read_bridge_mmio_pref(child);
+
+ if (dev->transparent) {
+ for (i = 3; i < PCI_BUS_NUM_RESOURCES; i++) {
+ child->resource[i] = child->parent->resource[i - 3];
+ if (child->resource[i])
+ dev_printk(KERN_DEBUG, &dev->dev,
+ " bridge window %pR (subtractive decode)\n",
+ child->resource[i]);
+ }
+ }
}
static struct pci_bus * pci_alloc_bus(void)
^ permalink raw reply related
* [PATCH v4 3/5] PCI: add pci_bus_for_each_resource(), remove direct bus->resource[] refs
From: Bjorn Helgaas @ 2010-02-17 20:20 UTC (permalink / raw)
To: Jesse Barnes
Cc: Matthew Garrett, Tony Luck, linuxppc-dev, linux-pci, Peter Haight,
Gary Hade, linux-kernel, linux-acpi, linux-am33-list,
Linus Torvalds, Ingo Molnar, Yinghai Lu, Larry Finger
In-Reply-To: <20100217201654.4013.70201.stgit@bob.kio>
No functional change; this converts loops that iterate from 0 to
PCI_BUS_NUM_RESOURCES through pci_bus resource[] table to use the
pci_bus_for_each_resource() iterator instead.
This doesn't change the way resources are stored; it merely removes
dependencies on the fact that they're in a table.
Signed-off-by: Bjorn Helgaas <bjorn.helgaas@hp.com>
---
arch/ia64/pci/pci.c | 5 ++---
arch/mn10300/unit-asb2305/pci.c | 6 ++----
arch/powerpc/kernel/pci-common.c | 11 ++++-------
arch/powerpc/platforms/fsl_uli1575.c | 12 ++++++------
drivers/pci/bus.c | 4 ++--
drivers/pci/hotplug/shpchp_sysfs.c | 9 +++------
drivers/pci/pci.c | 5 ++---
drivers/pci/setup-bus.c | 10 ++++------
drivers/pcmcia/rsrc_nonstatic.c | 3 +--
drivers/pcmcia/yenta_socket.c | 5 +++--
include/linux/pci.h | 3 +++
11 files changed, 32 insertions(+), 41 deletions(-)
diff --git a/arch/ia64/pci/pci.c b/arch/ia64/pci/pci.c
index 783c83b..89f957c 100644
--- a/arch/ia64/pci/pci.c
+++ b/arch/ia64/pci/pci.c
@@ -452,13 +452,12 @@ EXPORT_SYMBOL(pcibios_bus_to_resource);
static int __devinit is_valid_resource(struct pci_dev *dev, int idx)
{
unsigned int i, type_mask = IORESOURCE_IO | IORESOURCE_MEM;
- struct resource *devr = &dev->resource[idx];
+ struct resource *devr = &dev->resource[idx], *busr;
if (!dev->bus)
return 0;
- for (i=0; i<PCI_BUS_NUM_RESOURCES; i++) {
- struct resource *busr = dev->bus->resource[i];
+ pci_bus_for_each_resource(dev->bus, busr, i) {
if (!busr || ((busr->flags ^ devr->flags) & type_mask))
continue;
if ((devr->start) && (devr->start >= busr->start) &&
diff --git a/arch/mn10300/unit-asb2305/pci.c b/arch/mn10300/unit-asb2305/pci.c
index 2cb7e75..6d8720a 100644
--- a/arch/mn10300/unit-asb2305/pci.c
+++ b/arch/mn10300/unit-asb2305/pci.c
@@ -331,12 +331,10 @@ static int __init pci_check_direct(void)
static int __devinit is_valid_resource(struct pci_dev *dev, int idx)
{
unsigned int i, type_mask = IORESOURCE_IO | IORESOURCE_MEM;
- struct resource *devr = &dev->resource[idx];
+ struct resource *devr = &dev->resource[idx], *busr;
if (dev->bus) {
- for (i = 0; i < PCI_BUS_NUM_RESOURCES; i++) {
- struct resource *busr = dev->bus->resource[i];
-
+ pci_bus_for_each_resource(dev->bus, busr, i) {
if (!busr || (busr->flags ^ devr->flags) & type_mask)
continue;
diff --git a/arch/powerpc/kernel/pci-common.c b/arch/powerpc/kernel/pci-common.c
index e640810..2597f95 100644
--- a/arch/powerpc/kernel/pci-common.c
+++ b/arch/powerpc/kernel/pci-common.c
@@ -1047,10 +1047,8 @@ static void __devinit pcibios_fixup_bridge(struct pci_bus *bus)
struct pci_dev *dev = bus->self;
- for (i = 0; i < PCI_BUS_NUM_RESOURCES; ++i) {
- if ((res = bus->resource[i]) == NULL)
- continue;
- if (!res->flags)
+ pci_bus_for_each_resource(bus, res, i) {
+ if (!res || !res->flags)
continue;
if (i >= 3 && bus->self->transparent)
continue;
@@ -1277,9 +1275,8 @@ void pcibios_allocate_bus_resources(struct pci_bus *bus)
pr_debug("PCI: Allocating bus resources for %04x:%02x...\n",
pci_domain_nr(bus), bus->number);
- for (i = 0; i < PCI_BUS_NUM_RESOURCES; ++i) {
- if ((res = bus->resource[i]) == NULL || !res->flags
- || res->start > res->end || res->parent)
+ pci_bus_for_each_resource(bus, res, i) {
+ if (!res || !res->flags || res->start > res->end || res->parent)
continue;
if (bus->parent == NULL)
pr = (res->flags & IORESOURCE_IO) ?
diff --git a/arch/powerpc/platforms/fsl_uli1575.c b/arch/powerpc/platforms/fsl_uli1575.c
index fd23a1d..8b0c208 100644
--- a/arch/powerpc/platforms/fsl_uli1575.c
+++ b/arch/powerpc/platforms/fsl_uli1575.c
@@ -222,6 +222,7 @@ static void __devinit quirk_final_uli5249(struct pci_dev *dev)
int i;
u8 *dummy;
struct pci_bus *bus = dev->bus;
+ struct resource *res;
resource_size_t end = 0;
for (i = PCI_BRIDGE_RESOURCES; i < PCI_BRIDGE_RESOURCES+3; i++) {
@@ -230,13 +231,12 @@ static void __devinit quirk_final_uli5249(struct pci_dev *dev)
end = pci_resource_end(dev, i);
}
- for (i = 0; i < PCI_BUS_NUM_RESOURCES; i++) {
- if ((bus->resource[i]) &&
- (bus->resource[i]->flags & IORESOURCE_MEM)) {
- if (bus->resource[i]->end == end)
- dummy = ioremap(bus->resource[i]->start, 0x4);
+ pci_bus_for_each_resource(bus, res, i) {
+ if (res && res->flags & IORESOURCE_MEM) {
+ if (res->end == end)
+ dummy = ioremap(res->start, 0x4);
else
- dummy = ioremap(bus->resource[i]->end - 3, 0x4);
+ dummy = ioremap(res->end - 3, 0x4);
if (dummy) {
in_8(dummy);
iounmap(dummy);
diff --git a/drivers/pci/bus.c b/drivers/pci/bus.c
index a26135b..e75d219 100644
--- a/drivers/pci/bus.c
+++ b/drivers/pci/bus.c
@@ -43,6 +43,7 @@ pci_bus_alloc_resource(struct pci_bus *bus, struct resource *res,
void *alignf_data)
{
int i, ret = -ENOMEM;
+ struct resource *r;
resource_size_t max = -1;
type_mask |= IORESOURCE_IO | IORESOURCE_MEM;
@@ -51,8 +52,7 @@ pci_bus_alloc_resource(struct pci_bus *bus, struct resource *res,
if (!(res->flags & IORESOURCE_MEM_64))
max = PCIBIOS_MAX_MEM_32;
- for (i = 0; i < PCI_BUS_NUM_RESOURCES; i++) {
- struct resource *r = bus->resource[i];
+ pci_bus_for_each_resource(bus, r, i) {
if (!r)
continue;
diff --git a/drivers/pci/hotplug/shpchp_sysfs.c b/drivers/pci/hotplug/shpchp_sysfs.c
index 29fa9d2..071b7dc 100644
--- a/drivers/pci/hotplug/shpchp_sysfs.c
+++ b/drivers/pci/hotplug/shpchp_sysfs.c
@@ -47,8 +47,7 @@ static ssize_t show_ctrl (struct device *dev, struct device_attribute *attr, cha
bus = pdev->subordinate;
out += sprintf(buf, "Free resources: memory\n");
- for (index = 0; index < PCI_BUS_NUM_RESOURCES; index++) {
- res = bus->resource[index];
+ pci_bus_for_each_resource(bus, res, index) {
if (res && (res->flags & IORESOURCE_MEM) &&
!(res->flags & IORESOURCE_PREFETCH)) {
out += sprintf(out, "start = %8.8llx, "
@@ -58,8 +57,7 @@ static ssize_t show_ctrl (struct device *dev, struct device_attribute *attr, cha
}
}
out += sprintf(out, "Free resources: prefetchable memory\n");
- for (index = 0; index < PCI_BUS_NUM_RESOURCES; index++) {
- res = bus->resource[index];
+ pci_bus_for_each_resource(bus, res, index) {
if (res && (res->flags & IORESOURCE_MEM) &&
(res->flags & IORESOURCE_PREFETCH)) {
out += sprintf(out, "start = %8.8llx, "
@@ -69,8 +67,7 @@ static ssize_t show_ctrl (struct device *dev, struct device_attribute *attr, cha
}
}
out += sprintf(out, "Free resources: IO\n");
- for (index = 0; index < PCI_BUS_NUM_RESOURCES; index++) {
- res = bus->resource[index];
+ pci_bus_for_each_resource(bus, res, index) {
if (res && (res->flags & IORESOURCE_IO)) {
out += sprintf(out, "start = %8.8llx, "
"length = %8.8llx\n",
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index d62a5de..f4a2738 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -386,10 +386,9 @@ pci_find_parent_resource(const struct pci_dev *dev, struct resource *res)
{
const struct pci_bus *bus = dev->bus;
int i;
- struct resource *best = NULL;
+ struct resource *best = NULL, *r;
- for(i = 0; i < PCI_BUS_NUM_RESOURCES; i++) {
- struct resource *r = bus->resource[i];
+ pci_bus_for_each_resource(bus, r, i) {
if (!r)
continue;
if (res->start && !(res->start >= r->start && res->end <= r->end))
diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c
index 743ed8c..bf32f07 100644
--- a/drivers/pci/setup-bus.c
+++ b/drivers/pci/setup-bus.c
@@ -387,8 +387,7 @@ static struct resource *find_free_bus_resource(struct pci_bus *bus, unsigned lon
unsigned long type_mask = IORESOURCE_IO | IORESOURCE_MEM |
IORESOURCE_PREFETCH;
- for (i = 0; i < PCI_BUS_NUM_RESOURCES; i++) {
- r = bus->resource[i];
+ pci_bus_for_each_resource(bus, r, i) {
if (r == &ioport_resource || r == &iomem_resource)
continue;
if (r && (r->flags & type_mask) == type && !r->parent)
@@ -803,11 +802,10 @@ static void __ref pci_bus_release_bridge_resources(struct pci_bus *bus,
static void pci_bus_dump_res(struct pci_bus *bus)
{
- int i;
-
- for (i = 0; i < PCI_BUS_NUM_RESOURCES; i++) {
- struct resource *res = bus->resource[i];
+ struct resource *res;
+ int i;
+ pci_bus_for_each_resource(bus, res, i) {
if (!res || !res->end || !res->flags)
continue;
diff --git a/drivers/pcmcia/rsrc_nonstatic.c b/drivers/pcmcia/rsrc_nonstatic.c
index 45d75dc..c67638f 100644
--- a/drivers/pcmcia/rsrc_nonstatic.c
+++ b/drivers/pcmcia/rsrc_nonstatic.c
@@ -803,8 +803,7 @@ static int nonstatic_autoadd_resources(struct pcmcia_socket *s)
return -EINVAL;
#endif
- for (i = 0; i < PCI_BUS_NUM_RESOURCES; i++) {
- res = s->cb_dev->bus->resource[i];
+ pci_bus_for_each_resource(s->cb_dev->bus, res, i) {
if (!res)
continue;
diff --git a/drivers/pcmcia/yenta_socket.c b/drivers/pcmcia/yenta_socket.c
index e4d12ac..1f2039d 100644
--- a/drivers/pcmcia/yenta_socket.c
+++ b/drivers/pcmcia/yenta_socket.c
@@ -649,9 +649,10 @@ static int yenta_search_one_res(struct resource *root, struct resource *res,
static int yenta_search_res(struct yenta_socket *socket, struct resource *res,
u32 min)
{
+ struct resource *root;
int i;
- for (i = 0; i < PCI_BUS_NUM_RESOURCES; i++) {
- struct resource *root = socket->dev->bus->resource[i];
+
+ pci_bus_for_each_resource(socket->dev->bus, root, i) {
if (!root)
continue;
diff --git a/include/linux/pci.h b/include/linux/pci.h
index df2a12f..8891d3b 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -828,6 +828,9 @@ int pci_request_selected_regions_exclusive(struct pci_dev *, int, const char *);
void pci_release_selected_regions(struct pci_dev *, int);
/* drivers/pci/bus.c */
+#define pci_bus_for_each_resource(bus, res, i) \
+ for (i = 0; res = bus->resource[i], i < PCI_BUS_NUM_RESOURCES; i++)
+
int __must_check pci_bus_alloc_resource(struct pci_bus *bus,
struct resource *res, resource_size_t size,
resource_size_t align, resource_size_t min,
^ permalink raw reply related
* [PATCH v4 4/5] PCI: augment bus resource table with a list
From: Bjorn Helgaas @ 2010-02-17 20:20 UTC (permalink / raw)
To: Jesse Barnes
Cc: Matthew Garrett, Tony Luck, linuxppc-dev, linux-pci, Peter Haight,
Gary Hade, linux-kernel, linux-acpi, linux-am33-list,
Linus Torvalds, Ingo Molnar, Yinghai Lu, Larry Finger
In-Reply-To: <20100217201654.4013.70201.stgit@bob.kio>
Previously we used a table of size PCI_BUS_NUM_RESOURCES (16) for resources
forwarded to a bus by its upstream bridge. We've increased this size
several times when the table overflowed.
But there's no good limit on the number of resources because host bridges
and subtractive decode bridges can forward any number of ranges to their
secondary buses.
This patch reduces the table to only PCI_BRIDGE_RESOURCE_NUM (4) entries,
which corresponds to the number of windows a PCI-to-PCI (3) or CardBus (4)
bridge can positively decode. Any additional resources, e.g., PCI host
bridge windows or subtractively-decoded regions, are kept in a list.
I'd prefer a single list rather than this split table/list approach, but
that requires simultaneous changes to every architecture. This approach
only requires immediate changes where we set up (a) host bridges with more
than four windows and (b) subtractive-decode P2P bridges, and we can
incrementally change other architectures to use the list.
Signed-off-by: Bjorn Helgaas <bjorn.helgaas@hp.com>
---
arch/ia64/pci/pci.c | 12 +++---------
arch/x86/pci/acpi.c | 33 ++++-----------------------------
arch/x86/pci/bus_numa.c | 3 ++-
arch/x86/pci/bus_numa.h | 3 +--
drivers/pci/bus.c | 45 +++++++++++++++++++++++++++++++++++++++++++++
drivers/pci/probe.c | 17 +++++++++++++----
include/linux/pci.h | 35 +++++++++++++++++++++++++++++------
7 files changed, 97 insertions(+), 51 deletions(-)
diff --git a/arch/ia64/pci/pci.c b/arch/ia64/pci/pci.c
index 89f957c..64aff52 100644
--- a/arch/ia64/pci/pci.c
+++ b/arch/ia64/pci/pci.c
@@ -320,9 +320,9 @@ static __devinit acpi_status add_window(struct acpi_resource *res, void *data)
static void __devinit
pcibios_setup_root_windows(struct pci_bus *bus, struct pci_controller *ctrl)
{
- int i, j;
+ int i;
- j = 0;
+ pci_bus_remove_resources(bus);
for (i = 0; i < ctrl->windows; i++) {
struct resource *res = &ctrl->window[i].resource;
/* HP's firmware has a hack to work around a Windows bug.
@@ -330,13 +330,7 @@ pcibios_setup_root_windows(struct pci_bus *bus, struct pci_controller *ctrl)
if ((res->flags & IORESOURCE_MEM) &&
(res->end - res->start < 16))
continue;
- if (j >= PCI_BUS_NUM_RESOURCES) {
- dev_warn(&bus->dev,
- "ignoring host bridge window %pR (no space)\n",
- res);
- continue;
- }
- bus->resource[j++] = res;
+ pci_bus_add_resource(bus, res, 0);
}
}
diff --git a/arch/x86/pci/acpi.c b/arch/x86/pci/acpi.c
index 959e548..a2f8cdb 100644
--- a/arch/x86/pci/acpi.c
+++ b/arch/x86/pci/acpi.c
@@ -45,20 +45,6 @@ count_resource(struct acpi_resource *acpi_res, void *data)
return AE_OK;
}
-static int
-bus_has_transparent_bridge(struct pci_bus *bus)
-{
- struct pci_dev *dev;
-
- list_for_each_entry(dev, &bus->devices, bus_list) {
- u16 class = dev->class >> 8;
-
- if (class == PCI_CLASS_BRIDGE_PCI && dev->transparent)
- return true;
- }
- return false;
-}
-
static void
align_resource(struct acpi_device *bridge, struct resource *res)
{
@@ -92,12 +78,8 @@ setup_resource(struct acpi_resource *acpi_res, void *data)
acpi_status status;
unsigned long flags;
struct resource *root;
- int max_root_bus_resources = PCI_BUS_NUM_RESOURCES;
u64 start, end;
- if (bus_has_transparent_bridge(info->bus))
- max_root_bus_resources -= 3;
-
status = resource_to_addr(acpi_res, &addr);
if (!ACPI_SUCCESS(status))
return AE_OK;
@@ -115,15 +97,6 @@ setup_resource(struct acpi_resource *acpi_res, void *data)
start = addr.minimum + addr.translation_offset;
end = start + addr.address_length - 1;
- if (info->res_num >= max_root_bus_resources) {
- if (pci_probe & PCI_USE__CRS)
- printk(KERN_WARNING "PCI: Failed to allocate "
- "0x%lx-0x%lx from %s for %s due to _CRS "
- "returning more than %d resource descriptors\n",
- (unsigned long) start, (unsigned long) end,
- root->name, info->name, max_root_bus_resources);
- return AE_OK;
- }
res = &info->res[info->res_num];
res->name = info->name;
@@ -143,7 +116,7 @@ setup_resource(struct acpi_resource *acpi_res, void *data)
dev_err(&info->bridge->dev,
"can't allocate host bridge window %pR\n", res);
} else {
- info->bus->resource[info->res_num] = res;
+ pci_bus_add_resource(info->bus, res, 0);
info->res_num++;
if (addr.translation_offset)
dev_info(&info->bridge->dev, "host bridge window %pR "
@@ -164,7 +137,9 @@ get_current_resources(struct acpi_device *device, int busnum,
struct pci_root_info info;
size_t size;
- if (!(pci_probe & PCI_USE__CRS))
+ if (pci_probe & PCI_USE__CRS)
+ pci_bus_remove_resources(bus);
+ else
dev_info(&device->dev,
"ignoring host bridge windows from ACPI; "
"boot with \"pci=use_crs\" to use them\n");
diff --git a/arch/x86/pci/bus_numa.c b/arch/x86/pci/bus_numa.c
index f939d60..12d54ff 100644
--- a/arch/x86/pci/bus_numa.c
+++ b/arch/x86/pci/bus_numa.c
@@ -36,13 +36,14 @@ void x86_pci_root_bus_res_quirks(struct pci_bus *b)
printk(KERN_DEBUG "PCI: peer root bus %02x res updated from pci conf\n",
b->number);
+ pci_bus_remove_resources(b);
info = &pci_root_info[i];
for (j = 0; j < info->res_num; j++) {
struct resource *res;
struct resource *root;
res = &info->res[j];
- b->resource[j] = res;
+ pci_bus_add_resource(b, res, 0);
if (res->flags & IORESOURCE_IO)
root = &ioport_resource;
else
diff --git a/arch/x86/pci/bus_numa.h b/arch/x86/pci/bus_numa.h
index adbc23f..731b64e 100644
--- a/arch/x86/pci/bus_numa.h
+++ b/arch/x86/pci/bus_numa.h
@@ -2,8 +2,7 @@
/*
* sub bus (transparent) will use entres from 3 to store extra from
- * root, so need to make sure we have enough slot there, Should we
- * increase PCI_BUS_NUM_RESOURCES?
+ * root, so need to make sure we have enough slot there.
*/
#define RES_NUM 16
struct pci_root_info {
diff --git a/drivers/pci/bus.c b/drivers/pci/bus.c
index e75d219..087c732 100644
--- a/drivers/pci/bus.c
+++ b/drivers/pci/bus.c
@@ -17,6 +17,51 @@
#include "pci.h"
+void pci_bus_add_resource(struct pci_bus *bus, struct resource *res,
+ unsigned int flags)
+{
+ struct pci_bus_resource *bus_res;
+
+ bus_res = kzalloc(sizeof(struct pci_bus_resource), GFP_KERNEL);
+ if (!bus_res) {
+ dev_err(&bus->dev, "can't add %pR resource\n", res);
+ return;
+ }
+
+ bus_res->res = res;
+ bus_res->flags = flags;
+ list_add_tail(&bus_res->list, &bus->resources);
+}
+
+struct resource *pci_bus_resource_n(const struct pci_bus *bus, int n)
+{
+ struct pci_bus_resource *bus_res;
+
+ if (n < PCI_BRIDGE_RESOURCE_NUM)
+ return bus->resource[n];
+
+ n -= PCI_BRIDGE_RESOURCE_NUM;
+ list_for_each_entry(bus_res, &bus->resources, list) {
+ if (n-- == 0)
+ return bus_res->res;
+ }
+ return NULL;
+}
+
+void pci_bus_remove_resources(struct pci_bus *bus)
+{
+ struct pci_bus_resource *bus_res, *tmp;
+ int i;
+
+ for (i = 0; i < PCI_BRIDGE_RESOURCE_NUM; i++)
+ bus->resource[i] = 0;
+
+ list_for_each_entry_safe(bus_res, tmp, &bus->resources, list) {
+ list_del(&bus_res->list);
+ kfree(bus_res);
+ }
+}
+
/**
* pci_bus_alloc_resource - allocate a resource from a parent bus
* @bus: PCI bus
diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
index 70c4ed2..270d069 100644
--- a/drivers/pci/probe.c
+++ b/drivers/pci/probe.c
@@ -89,6 +89,7 @@ static void release_pcibus_dev(struct device *dev)
if (pci_bus->bridge)
put_device(pci_bus->bridge);
+ pci_bus_remove_resources(pci_bus);
kfree(pci_bus);
}
@@ -394,6 +395,7 @@ static void __devinit pci_read_bridge_mmio_pref(struct pci_bus *child)
void __devinit pci_read_bridge_bases(struct pci_bus *child)
{
struct pci_dev *dev = child->self;
+ struct resource *res;
int i;
if (pci_is_root_bus(child)) /* It's a host bus, nothing to read */
@@ -403,17 +405,23 @@ void __devinit pci_read_bridge_bases(struct pci_bus *child)
child->secondary, child->subordinate,
dev->transparent ? " (subtractive decode)" : "");
+ pci_bus_remove_resources(child);
+ for (i = 0; i < PCI_BRIDGE_RESOURCE_NUM; i++)
+ child->resource[i] = &dev->resource[PCI_BRIDGE_RESOURCES+i];
+
pci_read_bridge_io(child);
pci_read_bridge_mmio(child);
pci_read_bridge_mmio_pref(child);
if (dev->transparent) {
- for (i = 3; i < PCI_BUS_NUM_RESOURCES; i++) {
- child->resource[i] = child->parent->resource[i - 3];
- if (child->resource[i])
+ pci_bus_for_each_resource(child->parent, res, i) {
+ if (res) {
+ pci_bus_add_resource(child, res,
+ PCI_SUBTRACTIVE_DECODE);
dev_printk(KERN_DEBUG, &dev->dev,
" bridge window %pR (subtractive decode)\n",
- child->resource[i]);
+ res);
+ }
}
}
}
@@ -428,6 +436,7 @@ static struct pci_bus * pci_alloc_bus(void)
INIT_LIST_HEAD(&b->children);
INIT_LIST_HEAD(&b->devices);
INIT_LIST_HEAD(&b->slots);
+ INIT_LIST_HEAD(&b->resources);
b->max_bus_speed = PCI_SPEED_UNKNOWN;
b->cur_bus_speed = PCI_SPEED_UNKNOWN;
}
diff --git a/include/linux/pci.h b/include/linux/pci.h
index 8891d3b..2af5eab 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -363,9 +363,26 @@ static inline void pci_add_saved_cap(struct pci_dev *pci_dev,
hlist_add_head(&new_cap->next, &pci_dev->saved_cap_space);
}
-#ifndef PCI_BUS_NUM_RESOURCES
-#define PCI_BUS_NUM_RESOURCES 16
-#endif
+/*
+ * The first PCI_BRIDGE_RESOURCE_NUM PCI bus resources (those that correspond
+ * to P2P or CardBus bridge windows) go in a table. Additional ones (for
+ * buses below host bridges or subtractive decode bridges) go in the list.
+ * Use pci_bus_for_each_resource() to iterate through all the resources.
+ */
+
+/*
+ * PCI_SUBTRACTIVE_DECODE means the bridge forwards the window implicitly
+ * and there's no way to program the bridge with the details of the window.
+ * This does not apply to ACPI _CRS windows, even with the _DEC subtractive-
+ * decode bit set, because they are explicit and can be programmed with _SRS.
+ */
+#define PCI_SUBTRACTIVE_DECODE 0x1
+
+struct pci_bus_resource {
+ struct list_head list;
+ struct resource *res;
+ unsigned int flags;
+};
#define PCI_REGION_FLAG_MASK 0x0fU /* These bits of resource flags tell us the PCI region flags */
@@ -376,8 +393,8 @@ struct pci_bus {
struct list_head devices; /* list of devices on this bus */
struct pci_dev *self; /* bridge device as seen by parent */
struct list_head slots; /* list of slots on this bus */
- struct resource *resource[PCI_BUS_NUM_RESOURCES];
- /* address space routed to this bus */
+ struct resource *resource[PCI_BRIDGE_RESOURCE_NUM];
+ struct list_head resources; /* address space routed to this bus */
struct pci_ops *ops; /* configuration access functions */
void *sysdata; /* hook for sys-specific extension */
@@ -828,8 +845,14 @@ int pci_request_selected_regions_exclusive(struct pci_dev *, int, const char *);
void pci_release_selected_regions(struct pci_dev *, int);
/* drivers/pci/bus.c */
+void pci_bus_add_resource(struct pci_bus *bus, struct resource *res, unsigned int flags);
+struct resource *pci_bus_resource_n(const struct pci_bus *bus, int n);
+void pci_bus_remove_resources(struct pci_bus *bus);
+
#define pci_bus_for_each_resource(bus, res, i) \
- for (i = 0; res = bus->resource[i], i < PCI_BUS_NUM_RESOURCES; i++)
+ for (i = 0; \
+ (res = pci_bus_resource_n(bus, i)) || i < PCI_BRIDGE_RESOURCE_NUM; \
+ i++)
int __must_check pci_bus_alloc_resource(struct pci_bus *bus,
struct resource *res, resource_size_t size,
^ permalink raw reply related
* [PATCH v4 5/5] x86/PCI: use host bridge _CRS info by default on 2008 and newer machines
From: Bjorn Helgaas @ 2010-02-17 20:20 UTC (permalink / raw)
To: Jesse Barnes
Cc: Matthew Garrett, Tony Luck, linuxppc-dev, linux-pci, Peter Haight,
Gary Hade, linux-kernel, linux-acpi, linux-am33-list,
Linus Torvalds, Ingo Molnar, Yinghai Lu, Larry Finger
In-Reply-To: <20100217201654.4013.70201.stgit@bob.kio>
The main benefit of using ACPI host bridge window information is that
we can do better resource allocation in systems with multiple host bridges,
e.g., http://bugzilla.kernel.org/show_bug.cgi?id=14183
Sometimes we need _CRS information even if we only have one host bridge,
e.g., https://bugs.launchpad.net/ubuntu/+source/linux/+bug/341681
Most of these systems are relatively new, so this patch turns on
"pci=use_crs" only on machines with a BIOS date of 2008 or newer.
Signed-off-by: Bjorn Helgaas <bjorn.helgaas@hp.com>
---
Documentation/kernel-parameters.txt | 8 ++++-
arch/ia64/include/asm/acpi.h | 1 +
arch/x86/include/asm/pci_x86.h | 1 +
arch/x86/pci/acpi.c | 53 +++++++++++++++++++++++++++++++----
arch/x86/pci/common.c | 3 ++
drivers/acpi/pci_root.c | 1 +
include/acpi/acpi_drivers.h | 1 +
7 files changed, 60 insertions(+), 8 deletions(-)
diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt
index 01e2a98..6913e9a 100644
--- a/Documentation/kernel-parameters.txt
+++ b/Documentation/kernel-parameters.txt
@@ -1939,8 +1939,12 @@ and is between 256 and 4096 characters. It is defined in the file
IRQ routing is enabled.
noacpi [X86] Do not use ACPI for IRQ routing
or for PCI scanning.
- use_crs [X86] Use _CRS for PCI resource
- allocation.
+ use_crs [X86] Use PCI host bridge window information
+ from ACPI. On BIOSes from 2008 or later, this
+ is enabled by default. If you need to use this,
+ please report a bug.
+ nocrs [X86] Ignore PCI host bridge windows from ACPI.
+ If you need to use this, please report a bug.
routeirq Do IRQ routing for all PCI devices.
This is normally done in pci_enable_device(),
so this option is a temporary workaround
diff --git a/arch/ia64/include/asm/acpi.h b/arch/ia64/include/asm/acpi.h
index 7ae5889..7f2d7f2 100644
--- a/arch/ia64/include/asm/acpi.h
+++ b/arch/ia64/include/asm/acpi.h
@@ -97,6 +97,7 @@ ia64_acpi_release_global_lock (unsigned int *lock)
#endif
#define acpi_processor_cstate_check(x) (x) /* no idle limits on IA64 :) */
static inline void disable_acpi(void) { }
+static inline void pci_acpi_crs_quirks(void) { }
const char *acpi_get_sysname (void);
int acpi_request_vector (u32 int_type);
diff --git a/arch/x86/include/asm/pci_x86.h b/arch/x86/include/asm/pci_x86.h
index b4bf9a9..05b58cc 100644
--- a/arch/x86/include/asm/pci_x86.h
+++ b/arch/x86/include/asm/pci_x86.h
@@ -29,6 +29,7 @@
#define PCI_CHECK_ENABLE_AMD_MMCONF 0x20000
#define PCI_HAS_IO_ECS 0x40000
#define PCI_NOASSIGN_ROMS 0x80000
+#define PCI_ROOT_NO_CRS 0x100000
extern unsigned int pci_probe;
extern unsigned long pirq_table_addr;
diff --git a/arch/x86/pci/acpi.c b/arch/x86/pci/acpi.c
index a2f8cdb..5f11ff6 100644
--- a/arch/x86/pci/acpi.c
+++ b/arch/x86/pci/acpi.c
@@ -15,6 +15,51 @@ struct pci_root_info {
int busnum;
};
+static bool pci_use_crs = true;
+
+static int __init set_use_crs(const struct dmi_system_id *id)
+{
+ pci_use_crs = true;
+ return 0;
+}
+
+static const struct dmi_system_id pci_use_crs_table[] __initconst = {
+ /* http://bugzilla.kernel.org/show_bug.cgi?id=14183 */
+ {
+ .callback = set_use_crs,
+ .ident = "IBM System x3800",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "IBM"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "x3800"),
+ },
+ },
+ {}
+};
+
+void __init pci_acpi_crs_quirks(void)
+{
+ int year;
+
+ if (dmi_get_date(DMI_BIOS_DATE, &year, NULL, NULL) && year < 2008)
+ pci_use_crs = false;
+
+ dmi_check_system(pci_use_crs_table);
+
+ /*
+ * If the user specifies "pci=use_crs" or "pci=nocrs" explicitly, that
+ * takes precedence over anything we figured out above.
+ */
+ if (pci_probe & PCI_ROOT_NO_CRS)
+ pci_use_crs = false;
+ else if (pci_probe & PCI_USE__CRS)
+ pci_use_crs = true;
+
+ printk(KERN_INFO "PCI: %s host bridge windows from ACPI; "
+ "if necessary, use \"pci=%s\" and report a bug\n",
+ pci_use_crs ? "Using" : "Ignoring",
+ pci_use_crs ? "nocrs" : "use_crs");
+}
+
static acpi_status
resource_to_addr(struct acpi_resource *resource,
struct acpi_resource_address64 *addr)
@@ -106,7 +151,7 @@ setup_resource(struct acpi_resource *acpi_res, void *data)
res->child = NULL;
align_resource(info->bridge, res);
- if (!(pci_probe & PCI_USE__CRS)) {
+ if (!pci_use_crs) {
dev_printk(KERN_DEBUG, &info->bridge->dev,
"host bridge window %pR (ignored)\n", res);
return AE_OK;
@@ -137,12 +182,8 @@ get_current_resources(struct acpi_device *device, int busnum,
struct pci_root_info info;
size_t size;
- if (pci_probe & PCI_USE__CRS)
+ if (pci_use_crs)
pci_bus_remove_resources(bus);
- else
- dev_info(&device->dev,
- "ignoring host bridge windows from ACPI; "
- "boot with \"pci=use_crs\" to use them\n");
info.bridge = device;
info.bus = bus;
diff --git a/arch/x86/pci/common.c b/arch/x86/pci/common.c
index d2552c6..3736176 100644
--- a/arch/x86/pci/common.c
+++ b/arch/x86/pci/common.c
@@ -520,6 +520,9 @@ char * __devinit pcibios_setup(char *str)
} else if (!strcmp(str, "use_crs")) {
pci_probe |= PCI_USE__CRS;
return NULL;
+ } else if (!strcmp(str, "nocrs")) {
+ pci_probe |= PCI_ROOT_NO_CRS;
+ return NULL;
} else if (!strcmp(str, "earlydump")) {
pci_early_dump_regs = 1;
return NULL;
diff --git a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c
index 64ae2f2..4a46051 100644
--- a/drivers/acpi/pci_root.c
+++ b/drivers/acpi/pci_root.c
@@ -566,6 +566,7 @@ static int __init acpi_pci_root_init(void)
if (acpi_pci_disabled)
return 0;
+ pci_acpi_crs_quirks();
if (acpi_bus_register_driver(&acpi_pci_root_driver) < 0)
return -ENODEV;
diff --git a/include/acpi/acpi_drivers.h b/include/acpi/acpi_drivers.h
index f4906f6..3a4767c 100644
--- a/include/acpi/acpi_drivers.h
+++ b/include/acpi/acpi_drivers.h
@@ -104,6 +104,7 @@ int acpi_pci_bind_root(struct acpi_device *device);
struct pci_bus *pci_acpi_scan_root(struct acpi_device *device, int domain,
int bus);
+void pci_acpi_crs_quirks(void);
/* --------------------------------------------------------------------------
Processor
^ permalink raw reply related
* Re: [net-next-2.6 PATCH v2 3/3] fs_enet: add FEC TX buffer alignment workaround for MPC5121
From: Anatolij Gustschin @ 2010-02-17 21:31 UTC (permalink / raw)
To: Eric Dumazet
Cc: Wolfgang Denk, Detlev Zundel, netdev, linuxppc-dev,
David S. Miller, Piotr Ziecik
In-Reply-To: <1266419836.3075.12.camel@edumazet-laptop>
On Wed, 17 Feb 2010 16:17:16 +0100
Eric Dumazet <eric.dumazet@gmail.com> wrote:
> Le mercredi 17 f=C3=A9vrier 2010 =C3=A0 15:55 +0100, Anatolij Gustschin a=
=C3=A9crit :
...
> > +static struct sk_buff *tx_skb_align_workaround(struct net_device *dev,
> > + struct sk_buff *skb)
> > +{
> > + struct sk_buff *new_skb;
> > + struct fs_enet_private *fep =3D netdev_priv(dev);
> > +
> > + /* Alloc new skb */
> > + new_skb =3D dev_alloc_skb(ENET_RX_FRSIZE + 4);
>=20
>=20
> ENET_RX_FRSIZE looks strange in TX path
>=20
> Why not using skb->len + 4 instead of ENET_RX_FRSIZE + 4 ?
I will fix it.
> > + if (!new_skb) {
> > + dev_warn(fep->dev, "Memory squeeze, dropping tx packet.\n");
>=20
> I am just wondering if this is ratelimited ?
Right, it should be ratelimited, will fix it, too.
...
> > static int fs_enet_start_xmit(struct sk_buff *skb, struct net_device *=
dev)
> > {
> > struct fs_enet_private *fep =3D netdev_priv(dev);
> > @@ -588,6 +619,19 @@ static int fs_enet_start_xmit(struct sk_buff *skb,=
struct net_device *dev)
> > u16 sc;
> > unsigned long flags;
> > =20
> > +#ifdef CONFIG_FS_ENET_MPC5121_FEC
> > + if (((unsigned long)skb->data) & 0x3) {
> > + skb =3D tx_skb_align_workaround(dev, skb);
> > + if (!skb) {
> > + /*
> > + * We have lost packet due to memory allocation error
> > + * in tx_skb_align_workaround(). Hopefully original
> > + * skb is still valid, so try transmit it later.
> > + */
>=20
> Could you define 'try to transmit later' ?
> Who is responsible to trigger this event ?
The function returns NETDEV_TX_BUSY here, skb is not
consumed and will be requeued by sch_direct_xmit(), so
it is scheduled for resending later.
Thanks,
Anatolij
^ permalink raw reply
* [net-next-2.6 PATCH v3 3/3] fs_enet: add FEC TX buffer alignment workaround for MPC5121
From: Anatolij Gustschin @ 2010-02-17 22:08 UTC (permalink / raw)
To: netdev
Cc: Wolfgang Denk, Detlev Zundel, linuxppc-dev, Anatolij Gustschin,
David S. Miller, Piotr Ziecik
In-Reply-To: <1266418530-2727-4-git-send-email-agust@denx.de>
MPC5121 FEC requeries 4-byte alignmnent for TX data buffers.
This patch is a work around that copies misaligned tx packets
to an aligned skb before sending.
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>
---
Changes since v2:
- ratelimit warning message
- use skb->len + 4 as size for allocation of the new skb
with aligned buffer.
drivers/net/fs_enet/fs_enet-main.c | 47 ++++++++++++++++++++++++++++++++++++
1 files changed, 47 insertions(+), 0 deletions(-)
diff --git a/drivers/net/fs_enet/fs_enet-main.c b/drivers/net/fs_enet/fs_enet-main.c
index 4297021..0770e2f 100644
--- a/drivers/net/fs_enet/fs_enet-main.c
+++ b/drivers/net/fs_enet/fs_enet-main.c
@@ -580,6 +580,40 @@ void fs_cleanup_bds(struct net_device *dev)
/**********************************************************************************/
+#ifdef CONFIG_FS_ENET_MPC5121_FEC
+/*
+ * MPC5121 FEC requeries 4-byte alignment for TX data buffer!
+ */
+static struct sk_buff *tx_skb_align_workaround(struct net_device *dev,
+ struct sk_buff *skb)
+{
+ struct sk_buff *new_skb;
+ struct fs_enet_private *fep = netdev_priv(dev);
+
+ /* Alloc new skb */
+ new_skb = dev_alloc_skb(skb->len + 4);
+ if (!new_skb) {
+ if (net_ratelimit()) {
+ dev_warn(fep->dev,
+ "Memory squeeze, dropping tx packet.\n");
+ }
+ return NULL;
+ }
+
+ /* Make sure new skb is properly aligned */
+ skb_align(new_skb, 4);
+
+ /* Copy data to new skb ... */
+ skb_copy_from_linear_data(skb, new_skb->data, skb->len);
+ skb_put(new_skb, skb->len);
+
+ /* ... and free an old one */
+ dev_kfree_skb_any(skb);
+
+ return new_skb;
+}
+#endif
+
static int fs_enet_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
struct fs_enet_private *fep = netdev_priv(dev);
@@ -588,6 +622,19 @@ static int fs_enet_start_xmit(struct sk_buff *skb, struct net_device *dev)
u16 sc;
unsigned long flags;
+#ifdef CONFIG_FS_ENET_MPC5121_FEC
+ if (((unsigned long)skb->data) & 0x3) {
+ skb = tx_skb_align_workaround(dev, skb);
+ if (!skb) {
+ /*
+ * We have lost packet due to memory allocation error
+ * in tx_skb_align_workaround(). Hopefully original
+ * skb is still valid, so try transmit it later.
+ */
+ return NETDEV_TX_BUSY;
+ }
+ }
+#endif
spin_lock_irqsave(&fep->tx_lock, flags);
/*
--
1.6.3.3
^ permalink raw reply related
* Re: [PATCHv4 2/2] powerpc: implement arch_scale_smt_power for Power7
From: Michael Neuling @ 2010-02-17 22:20 UTC (permalink / raw)
To: Peter Zijlstra; +Cc: Ingo Molnar, linuxppc-dev, linux-kernel, ego
In-Reply-To: <1266142340.5273.418.camel@laptop>
> Suppose for a moment we have 2 threads (hot-unplugged thread 1 and 3, we
> can construct an equivalent but more complex example for 4 threads), and
> we have 4 tasks, 3 SCHED_OTHER of equal nice level and 1 SCHED_FIFO, the
> SCHED_FIFO task will consume exactly 50% walltime of whatever cpu it
> ends up on.
>
> In that situation, provided that each cpu's cpu_power is of equal
> measure, scale_rt_power() ensures that we run 2 SCHED_OTHER tasks on the
> cpu that doesn't run the RT task, and 1 SCHED_OTHER task next to the RT
> task, so that each task consumes 50%, which is all fair and proper.
>
> However, if you do the above, thread 0 will have +75% = 1.75 and thread
> 2 will have -75% = 0.25, then if the RT task will land on thread 0,
> we'll be having: 0.875 vs 0.25, or on thread 3, 1.75 vs 0.125. In either
> case thread 0 will receive too many (if not all) SCHED_OTHER tasks.
>
> That is, unless these threads 2 and 3 really are _that_ weak, at which
> point one wonders why IBM bothered with the silicon ;-)
Peter,
2 & 3 aren't weaker than 0 & 1 but....
The core has dynamic SMT mode switching which is controlled by the
hypervisor (IBM's PHYP). There are 3 SMT modes:
SMT1 uses thread 0
SMT2 uses threads 0 & 1
SMT4 uses threads 0, 1, 2 & 3
When in any particular SMT mode, all threads have the same performance
as each other (ie. at any moment in time, all threads perform the same).
The SMT mode switching works such that when linux has threads 2 & 3 idle
and 0 & 1 active, it will cede (H_CEDE hypercall) threads 2 and 3 in the
idle loop and the hypervisor will automatically switch to SMT2 for that
core (independent of other cores). The opposite is not true, so if
threads 0 & 1 are idle and 2 & 3 are active, we will stay in SMT4 mode.
Similarly if thread 0 is active and threads 1, 2 & 3 are idle, we'll go
into SMT1 mode.
If we can get the core into a lower SMT mode (SMT1 is best), the threads
will perform better (since they share less core resources). Hence when
we have idle threads, we want them to be the higher ones.
So to answer your question, threads 2 and 3 aren't weaker than the other
threads when in SMT4 mode. It's that if we idle threads 2 & 3, threads
0 & 1 will speed up since we'll move to SMT2 mode.
I'm pretty vague on linux scheduler details, so I'm a bit at sea as to
how to solve this. Can you suggest any mechanisms we currently have in
the kernel to reflect these properties, or do you think we need to
develop something new? If so, any pointers as to where we should look?
Thanks,
Mikey
^ permalink raw reply
* Re: [RFC PATCH] PCI-E broken on PPC (regression)
From: David Miller @ 2010-02-18 0:22 UTC (permalink / raw)
To: benh
Cc: linux-pci, fubar, jbarnes, ron.mercer, kaneshige.kenji,
linuxppc-dev, leitao
In-Reply-To: <1264558256.3601.153.camel@pasglop>
From: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Date: Wed, 27 Jan 2010 13:10:56 +1100
> I'll try do make ppc catch up with some of that see how it goes.
FWIW I'm taking care of syncing up sparc in this area
right now.
I just noticed the ->dma_mask assignment got moved as well.
Really, any change made to drivers/pci/probe.c is going to
require powerpc and sparc changes these days.
We should and will commonize our OpenFirmware PCI device probing code
under driver/pci but until that happens a real effort needs to be put
in place to at least ping Benjamin and myself when changes are going
in to drivers/pci/probe.c
Thanks.
^ permalink raw reply
* Re: [RFC PATCH] PCI-E broken on PPC (regression)
From: Jesse Barnes @ 2010-02-18 0:29 UTC (permalink / raw)
To: David Miller
Cc: fubar, linux-pci, ron.mercer, kaneshige.kenji, linuxppc-dev,
leitao
In-Reply-To: <20100217.162259.91779007.davem@davemloft.net>
On Wed, 17 Feb 2010 16:22:59 -0800 (PST)
David Miller <davem@davemloft.net> wrote:
> From: Benjamin Herrenschmidt <benh@kernel.crashing.org>
> Date: Wed, 27 Jan 2010 13:10:56 +1100
>
> > I'll try do make ppc catch up with some of that see how it goes.
>
> FWIW I'm taking care of syncing up sparc in this area
> right now.
>
> I just noticed the ->dma_mask assignment got moved as well.
>
> Really, any change made to drivers/pci/probe.c is going to
> require powerpc and sparc changes these days.
>
> We should and will commonize our OpenFirmware PCI device probing code
> under driver/pci but until that happens a real effort needs to be put
> in place to at least ping Benjamin and myself when changes are going
> in to drivers/pci/probe.c
Ok I'll include you guys on further changes.
--
Jesse Barnes, Intel Open Source Technology Center
^ permalink raw reply
* Re: [PATCH 1/5] powerpc/head fsl: fix the case where we are not in the first page
From: Kumar Gala @ 2010-02-18 3:07 UTC (permalink / raw)
To: Sebastian Andrzej Siewior; +Cc: linuxppc-dev, Sebastian Andrzej Siewior
In-Reply-To: <1263573697-17839-2-git-send-email-linuxppc-dev@ml.breakpoint.cc>
On Jan 15, 2010, at 10:41 AM, Sebastian Andrzej Siewior wrote:
> From: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
>=20
> During boot we change the mapping a few times until we have a =
"defined"
> mapping. During this procedure a small 4KiB mapping is created and =
after
> that one a 64MiB. Currently the offset of the 4KiB page in that we run
> is zero because the complete startup up code is in first page which
> starts at RPN zero.
> If the code is recycled and moved to another location then its =
execution
> will fail because the start address in the 64 MiB mapping is computed
> wrongly. It does not consider the offset to the page from the begin of
> the memory.
> This patch fixes this. Usually (system boot) r25 is zero so this does
> not change anything unless the code is recycled.
>=20
> Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
> ---
> arch/powerpc/kernel/head_fsl_booke.S | 1 +
> 1 files changed, 1 insertions(+), 0 deletions(-)
I don't get this. Why would would we not run at KERNELBASE?
- k
>=20
> diff --git a/arch/powerpc/kernel/head_fsl_booke.S =
b/arch/powerpc/kernel/head_fsl_booke.S
> index 7f4bd7f..799ddbe 100644
> --- a/arch/powerpc/kernel/head_fsl_booke.S
> +++ b/arch/powerpc/kernel/head_fsl_booke.S
> @@ -275,6 +275,7 @@ skpinv: addi r6,r6,1 =
/* Increment */
> 1: mflr r9
> rlwimi r6,r9,0,20,31
> addi r6,r6,(2f - 1b)
> + add r6, r6, r25
> mtspr SPRN_SRR0,r6
> mtspr SPRN_SRR1,r7
> rfi /* start execution out of =
TLB1[0] entry */
> --=20
> 1.6.2.5
^ permalink raw reply
* Re: [PATCH 2/5] powerpc/head fsl: move the temp 4KiB mapping to TLB0
From: Kumar Gala @ 2010-02-18 3:09 UTC (permalink / raw)
To: Sebastian Andrzej Siewior; +Cc: linuxppc-dev, Sebastian Andrzej Siewior
In-Reply-To: <1263573697-17839-3-git-send-email-linuxppc-dev@ml.breakpoint.cc>
On Jan 15, 2010, at 10:41 AM, Sebastian Andrzej Siewior wrote:
> From: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
>=20
> Right now the setup code takes ESEL of the current mapping and puts =
the
> temporary into ESEL (old_ESEL & 1 ) + 1 which is either one or two.
> This is actually not required since all slots in TLB0 are invalid by =
now
> and can be used.
> This patch moved the temp mapping to TLB0, ESEL[0]. The invalidation =
of
> TLB0 does not care about IPPROT so that part can go as well.
> The benefit is that now the setup code may set every slot of TLB1 =
while
> before that it was not allowed to touch ESEL one or two depending on =
the
> old_ESEL.
>=20
> Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
> ---
> arch/powerpc/kernel/head_fsl_booke.S | 20 +++++---------------
> 1 files changed, 5 insertions(+), 15 deletions(-)
this is problematic, we can't assume that TLB0 is safe. It possible =
some other software is running on a second core and does a broadcast =
tlbivax which will wipe what's in TLB0.
- k=
^ permalink raw reply
* Re: [PATCH 0/8] Update to GE powerpc/86xx based boards.
From: Kumar Gala @ 2010-02-18 3:17 UTC (permalink / raw)
To: Martyn Welch; +Cc: linuxppc-dev
In-Reply-To: <20100111121622.8306.87501.stgit@ES-J7S4D2J.amer.consind.ge.com>
On Jan 11, 2010, at 6:23 AM, Martyn Welch wrote:
> The following series implements some minor fixes and updates to the GE
> SBC310, SBC610 and PPC9A
>=20
> --=20
> Martyn Welch MEng MPhil MIET (Principal Software Engineer) =
T:+44(0)1327322748
> GE Fanuc Intelligent Platforms Ltd, |Registered in England and =
Wales
> Tove Valley Business Park, Towcester, |(3828642) at 100 =
Barbirolli Square,
> Northants, NN12 6PF, UK T:+44(0)1327359444 |Manchester,M2 3AB VAT:GB =
927559189
applied to next
- k
^ permalink raw reply
* Re: [PATCH 3/5] powerpc/head fsl: replace a hardcoded constant
From: Kumar Gala @ 2010-02-18 3:11 UTC (permalink / raw)
To: Sebastian Andrzej Siewior; +Cc: linuxppc-dev, Sebastian Andrzej Siewior
In-Reply-To: <1263573697-17839-4-git-send-email-linuxppc-dev@ml.breakpoint.cc>
On Jan 15, 2010, at 10:41 AM, Sebastian Andrzej Siewior wrote:
> From: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
>
> 24 is offset between the opcode past bl and past rfi. This makes it more
> obvious.
>
> Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
> ---
> arch/powerpc/kernel/head_fsl_booke.S | 4 ++--
> 1 files changed, 2 insertions(+), 2 deletions(-)
applied to next
- k
^ permalink raw reply
* Re: [PATCH] powerpc/85xx: Add NOR, LEDs and PIB support for MPC8568E-MDS boards
From: Kumar Gala @ 2010-02-18 3:19 UTC (permalink / raw)
To: Anton Vorontsov; +Cc: linuxppc-dev
In-Reply-To: <20100205210626.GA9882@oksana.dev.rtsoft.ru>
On Feb 5, 2010, at 3:06 PM, Anton Vorontsov wrote:
> This patch adds NOR Flash, LEDs and PIB support for MPC8568E-MDS
> boards. Plus, move bcsr node into localbus node, and add bcsr5
> gpio-controller node.
>=20
> Some platform code modifications were also needed.
>=20
> Signed-off-by: Anton Vorontsov <avorontsov@ru.mvista.com>
> ---
> arch/powerpc/boot/dts/mpc8568mds.dts | 65 =
+++++++++++++++++++++++++++-
> arch/powerpc/platforms/85xx/mpc85xx_mds.c | 3 +
> 2 files changed, 65 insertions(+), 3 deletions(-)
applied to next
- k=
^ 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