]> err.no Git - linux-2.6/commitdiff
ibm_newemac: Parameterize EMAC Multicast Match Handling
authorGrant Erickson <gerickson@nuovations.com>
Mon, 7 Jul 2008 22:03:11 +0000 (08:03 +1000)
committerBenjamin Herrenschmidt <benh@kernel.crashing.org>
Wed, 9 Jul 2008 06:30:46 +0000 (16:30 +1000)
Various instances of the EMAC core have varying: 1) number of address
match slots, 2) width of the registers for handling address match slots,
3) number of registers for handling address match slots and 4) base
offset for those registers.

As the driver stands today, it assumes that all EMACs have 4 IAHT and
GAHT 32-bit registers, starting at offset 0x30 from the register base,
with only 16-bits of each used for a total of 64 match slots.

The 405EX(r) and 460EX now use the EMAC4SYNC core rather than the EMAC4
core. This core has 8 IAHT and GAHT registers, starting at offset 0x80
from the register base, with ALL 32-bits of each used for a total of
256 match slots.

This adds a new compatible device tree entry "emac4sync" and a new,
related feature flag "EMAC_FTR_EMAC4SYNC" along with a series of macros
and inlines which supply the appropriate parameterized value based on
the presence or absence of the EMAC4SYNC feature.

The code has further been reworked where appropriate to use those macros
and inlines.

In addition, the register size passed to ioremap is now taken from the
device tree:

c4 for EMAC4SYNC cores
74 for EMAC4 cores
70 for EMAC cores

rather than sizeof (emac_regs).

Finally, the device trees have been updated with the appropriate compatible
entries and resource sizes.

This has been tested on an AMCC Haleakala board such that: 1) inbound
ICMP requests to 'haleakala.local' via MDNS from both Mac OS X 10.4.11
and Ubuntu 8.04 systems as well as 2) outbound ICMP requests from
'haleakala.local' to those same systems in the '.local' domain via MDNS
now work.

Signed-off-by: Grant Erickson <gerickson@nuovations.com>
Acked-by: Jeff Garzik <jgarzik@pobox.com>
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
13 files changed:
arch/powerpc/boot/dts/canyonlands.dts
arch/powerpc/boot/dts/glacier.dts
arch/powerpc/boot/dts/haleakala.dts
arch/powerpc/boot/dts/katmai.dts
arch/powerpc/boot/dts/kilauea.dts
arch/powerpc/boot/dts/makalu.dts
arch/powerpc/boot/dts/rainier.dts
arch/powerpc/boot/dts/sequoia.dts
arch/powerpc/boot/dts/taishan.dts
drivers/net/ibm_newemac/core.c
drivers/net/ibm_newemac/core.h
drivers/net/ibm_newemac/debug.c
drivers/net/ibm_newemac/emac.h

index f9fe0325215019b335307d5ef35cc5bb729656ac..79fe412c11c9c0d0dfcf14b737492095129c4197 100644 (file)
 
                        EMAC0: ethernet@ef600e00 {
                                device_type = "network";
-                               compatible = "ibm,emac-460ex", "ibm,emac4";
+                               compatible = "ibm,emac-460ex", "ibm,emac4sync";
                                interrupt-parent = <&EMAC0>;
                                interrupts = <0x0 0x1>;
                                #interrupt-cells = <1>;
                                #size-cells = <0>;
                                interrupt-map = </*Status*/ 0x0 &UIC2 0x10 0x4
                                                 /*Wake*/   0x1 &UIC2 0x14 0x4>;
-                               reg = <0xef600e00 0x00000070>;
+                               reg = <0xef600e00 0x000000c4>;
                                local-mac-address = [000000000000]; /* Filled in by U-Boot */
                                mal-device = <&MAL0>;
                                mal-tx-channel = <0>;
 
                        EMAC1: ethernet@ef600f00 {
                                device_type = "network";
-                               compatible = "ibm,emac-460ex", "ibm,emac4";
+                               compatible = "ibm,emac-460ex", "ibm,emac4sync";
                                interrupt-parent = <&EMAC1>;
                                interrupts = <0x0 0x1>;
                                #interrupt-cells = <1>;
                                #size-cells = <0>;
                                interrupt-map = </*Status*/ 0x0 &UIC2 0x11 0x4
                                                 /*Wake*/   0x1 &UIC2 0x15 0x4>;
-                               reg = <0xef600f00 0x00000070>;
+                               reg = <0xef600f00 0x000000c4>;
                                local-mac-address = [000000000000]; /* Filled in by U-Boot */
                                mal-device = <&MAL0>;
                                mal-tx-channel = <1>;
index 463650c5f61d9918c7053713aedc8939b507f3d6..24cf0dba120c89f53933250688783db89cbc627a 100644 (file)
                                #size-cells = <0>;
                                interrupt-map = </*Status*/ 0x0 &UIC2 0x10 0x4
                                                 /*Wake*/   0x1 &UIC2 0x14 0x4>;
-                               reg = <0xef600e00 0x00000070>;
+                               reg = <0xef600e00 0x00000074>;
                                local-mac-address = [000000000000]; /* Filled in by U-Boot */
                                mal-device = <&MAL0>;
                                mal-tx-channel = <0>;
                                #size-cells = <0>;
                                interrupt-map = </*Status*/ 0x0 &UIC2 0x11 0x4
                                                 /*Wake*/   0x1 &UIC2 0x15 0x4>;
-                               reg = <0xef600f00 0x00000070>;
+                               reg = <0xef600f00 0x00000074>;
                                local-mac-address = [000000000000]; /* Filled in by U-Boot */
                                mal-device = <&MAL0>;
                                mal-tx-channel = <1>;
                                #size-cells = <0>;
                                interrupt-map = </*Status*/ 0x0 &UIC2 0x12 0x4
                                                 /*Wake*/   0x1 &UIC2 0x16 0x4>;
-                               reg = <0xef601100 0x00000070>;
+                               reg = <0xef601100 0x00000074>;
                                local-mac-address = [000000000000]; /* Filled in by U-Boot */
                                mal-device = <&MAL0>;
                                mal-tx-channel = <2>;
                                #size-cells = <0>;
                                interrupt-map = </*Status*/ 0x0 &UIC2 0x13 0x4
                                                 /*Wake*/   0x1 &UIC2 0x17 0x4>;
-                               reg = <0xef601200 0x00000070>;
+                               reg = <0xef601200 0x00000074>;
                                local-mac-address = [000000000000]; /* Filled in by U-Boot */
                                mal-device = <&MAL0>;
                                mal-tx-channel = <3>;
index 2c2fceaabbcd8ce5464d1db28c55ab2bd4b2e22f..513bc43a71afab17b8784cb7a71c1115f78ea9ee 100644 (file)
                        EMAC0: ethernet@ef600900 {
                                linux,network-index = <0x0>;
                                device_type = "network";
-                               compatible = "ibm,emac-405exr", "ibm,emac4";
+                               compatible = "ibm,emac-405exr", "ibm,emac4sync";
                                interrupt-parent = <&EMAC0>;
                                interrupts = <0x0 0x1>;
                                #interrupt-cells = <1>;
                                #size-cells = <0>;
                                interrupt-map = </*Status*/ 0x0 &UIC0 0x18 0x4
                                                /*Wake*/  0x1 &UIC1 0x1d 0x4>;
-                               reg = <0xef600900 0x00000070>;
+                               reg = <0xef600900 0x000000c4>;
                                local-mac-address = [000000000000]; /* Filled in by U-Boot */
                                mal-device = <&MAL0>;
                                mal-tx-channel = <0>;
index b94bf61b9bccbeb720d06cda88430dc868f62589..077819bc3cbd0744c822f6037a5de76ff2a7e142 100644 (file)
                                compatible = "ibm,emac-440spe", "ibm,emac4";
                                interrupt-parent = <&UIC1>;
                                interrupts = <0x1c 0x4 0x1d 0x4>;
-                               reg = <0x10000800 0x00000070>;
+                               reg = <0x10000800 0x00000074>;
                                local-mac-address = [000000000000];
                                mal-device = <&MAL0>;
                                mal-tx-channel = <0>;
index 3ed6a8fee1d5147a85b333829537fee1029c2b63..dececc4b5ff280f8b40fc22be6c5bc8bdd5ac433 100644 (file)
                        EMAC0: ethernet@ef600900 {
                                linux,network-index = <0x0>;
                                device_type = "network";
-                               compatible = "ibm,emac-405ex", "ibm,emac4";
+                               compatible = "ibm,emac-405ex", "ibm,emac4sync";
                                interrupt-parent = <&EMAC0>;
                                interrupts = <0x0 0x1>;
                                #interrupt-cells = <1>;
                                #size-cells = <0>;
                                interrupt-map = </*Status*/ 0x0 &UIC0 0x18 0x4
                                                /*Wake*/  0x1 &UIC1 0x1d 0x4>;
-                               reg = <0xef600900 0x00000070>;
+                               reg = <0xef600900 0x000000c4>;
                                local-mac-address = [000000000000]; /* Filled in by U-Boot */
                                mal-device = <&MAL0>;
                                mal-tx-channel = <0>;
                        EMAC1: ethernet@ef600a00 {
                                linux,network-index = <0x1>;
                                device_type = "network";
-                               compatible = "ibm,emac-405ex", "ibm,emac4";
+                               compatible = "ibm,emac-405ex", "ibm,emac4sync";
                                interrupt-parent = <&EMAC1>;
                                interrupts = <0x0 0x1>;
                                #interrupt-cells = <1>;
                                #size-cells = <0>;
                                interrupt-map = </*Status*/ 0x0 &UIC0 0x19 0x4
                                                /*Wake*/  0x1 &UIC1 0x1f 0x4>;
-                               reg = <0xef600a00 0x00000070>;
+                               reg = <0xef600a00 0x000000c4>;
                                local-mac-address = [000000000000]; /* Filled in by U-Boot */
                                mal-device = <&MAL0>;
                                mal-tx-channel = <1>;
index 1dfcd7ed199c118ffd39a37c668a593f8c0e91a6..945508c7e7d8bbd9830876e8d708f56b92f0e6df 100644 (file)
                        EMAC0: ethernet@ef600900 {
                                linux,network-index = <0x0>;
                                device_type = "network";
-                               compatible = "ibm,emac-405ex", "ibm,emac4";
+                               compatible = "ibm,emac-405ex", "ibm,emac4sync";
                                interrupt-parent = <&EMAC0>;
                                interrupts = <0x0 0x1>;
                                #interrupt-cells = <1>;
                                #size-cells = <0>;
                                interrupt-map = </*Status*/ 0x0 &UIC0 0x18 0x4
                                                /*Wake*/  0x1 &UIC1 0x1d 0x4>;
-                               reg = <0xef600900 0x00000070>;
+                               reg = <0xef600900 0x000000c4>;
                                local-mac-address = [000000000000]; /* Filled in by U-Boot */
                                mal-device = <&MAL0>;
                                mal-tx-channel = <0>;
                        EMAC1: ethernet@ef600a00 {
                                linux,network-index = <0x1>;
                                device_type = "network";
-                               compatible = "ibm,emac-405ex", "ibm,emac4";
+                               compatible = "ibm,emac-405ex", "ibm,emac4sync";
                                interrupt-parent = <&EMAC1>;
                                interrupts = <0x0 0x1>;
                                #interrupt-cells = <1>;
                                #size-cells = <0>;
                                interrupt-map = </*Status*/ 0x0 &UIC0 0x19 0x4
                                                /*Wake*/  0x1 &UIC1 0x1f 0x4>;
-                               reg = <0xef600a00 0x00000070>;
+                               reg = <0xef600a00 0x000000c4>;
                                local-mac-address = [000000000000]; /* Filled in by U-Boot */
                                mal-device = <&MAL0>;
                                mal-tx-channel = <1>;
index 2afb63a42ea9a9648549d974c8c35d8ad656eb32..9684c80e40931927cc5879dfa3935eebd12b70aa 100644 (file)
                                #size-cells = <0>;
                                interrupt-map = </*Status*/ 0x0 &UIC0 0x18 0x4
                                                /*Wake*/  0x1 &UIC1 0x1d 0x4>;
-                               reg = <0xef600e00 0x00000070>;
+                               reg = <0xef600e00 0x00000074>;
                                local-mac-address = [000000000000];
                                mal-device = <&MAL0>;
                                mal-tx-channel = <0>;
                                #size-cells = <0>;
                                interrupt-map = </*Status*/ 0x0 &UIC0 0x19 0x4
                                                /*Wake*/  0x1 &UIC1 0x1f 0x4>;
-                               reg = <0xef600f00 0x00000070>;
+                               reg = <0xef600f00 0x00000074>;
                                local-mac-address = [000000000000];
                                mal-device = <&MAL0>;
                                mal-tx-channel = <1>;
index 149dabc5521772d964dd51eda2be7864255ac96e..72d15f075d34638a377b27d62355e1e38adf455c 100644 (file)
                                #size-cells = <0>;
                                interrupt-map = </*Status*/ 0x0 &UIC0 0x18 0x4
                                                /*Wake*/  0x1 &UIC1 0x1d 0x4>;
-                               reg = <0xef600e00 0x00000070>;
+                               reg = <0xef600e00 0x00000074>;
                                local-mac-address = [000000000000];
                                mal-device = <&MAL0>;
                                mal-tx-channel = <0>;
                                #size-cells = <0>;
                                interrupt-map = </*Status*/ 0x0 &UIC0 0x19 0x4
                                                /*Wake*/  0x1 &UIC1 0x1f 0x4>;
-                               reg = <0xef600f00 0x00000070>;
+                               reg = <0xef600f00 0x00000074>;
                                local-mac-address = [000000000000];
                                mal-device = <&MAL0>;
                                mal-tx-channel = <1>;
index d4867ded86997899564f5eceb339a3434bfe0d5e..058438f9629b814263f30623aebab22b9731903d 100644 (file)
                                compatible = "ibm,emac-440gx", "ibm,emac4";
                                interrupt-parent = <&UIC1>;
                                interrupts = <0x1c 0x4 0x1d 0x4>;
-                               reg = <0x40000800 0x00000070>;
+                               reg = <0x40000800 0x00000074>;
                                local-mac-address = [000000000000]; // Filled in by zImage
                                mal-device = <&MAL0>;
                                mal-tx-channel = <0>;
                                compatible = "ibm,emac-440gx", "ibm,emac4";
                                interrupt-parent = <&UIC1>;
                                interrupts = <0x1e 0x4 0x1f 0x4>;
-                               reg = <0x40000900 0x00000070>;
+                               reg = <0x40000900 0x00000074>;
                                local-mac-address = [000000000000]; // Filled in by zImage
                                mal-device = <&MAL0>;
                                mal-tx-channel = <1>;
                                compatible = "ibm,emac-440gx", "ibm,emac4";
                                interrupt-parent = <&UIC2>;
                                interrupts = <0x0 0x4 0x1 0x4>;
-                               reg = <0x40000c00 0x00000070>;
+                               reg = <0x40000c00 0x00000074>;
                                local-mac-address = [000000000000]; // Filled in by zImage
                                mal-device = <&MAL0>;
                                mal-tx-channel = <2>;
                                compatible = "ibm,emac-440gx", "ibm,emac4";
                                interrupt-parent = <&UIC2>;
                                interrupts = <0x2 0x4 0x3 0x4>;
-                               reg = <0x40000e00 0x00000070>;
+                               reg = <0x40000e00 0x00000074>;
                                local-mac-address = [000000000000]; // Filled in by zImage
                                mal-device = <&MAL0>;
                                mal-tx-channel = <3>;
index 5d2108c5ac7c872d32409de44edc22f07bf5620e..ed24a1d607dd011f6de6203f1453ecdcfe651bcb 100644 (file)
@@ -363,25 +363,31 @@ static int emac_reset(struct emac_instance *dev)
 
 static void emac_hash_mc(struct emac_instance *dev)
 {
-       struct emac_regs __iomem *p = dev->emacp;
-       u16 gaht[4] = { 0 };
+       const int regs = EMAC_XAHT_REGS(dev);
+       u32 *gaht_base = emac_gaht_base(dev);
+       u32 gaht_temp[regs];
        struct dev_mc_list *dmi;
+       int i;
 
        DBG(dev, "hash_mc %d" NL, dev->ndev->mc_count);
 
+       memset(gaht_temp, 0, sizeof (gaht_temp));
+
        for (dmi = dev->ndev->mc_list; dmi; dmi = dmi->next) {
-               int bit;
+               int slot, reg, mask;
                DBG2(dev, "mc %02x:%02x:%02x:%02x:%02x:%02x" NL,
                     dmi->dmi_addr[0], dmi->dmi_addr[1], dmi->dmi_addr[2],
                     dmi->dmi_addr[3], dmi->dmi_addr[4], dmi->dmi_addr[5]);
 
-               bit = 63 - (ether_crc(ETH_ALEN, dmi->dmi_addr) >> 26);
-               gaht[bit >> 4] |= 0x8000 >> (bit & 0x0f);
+               slot = EMAC_XAHT_CRC_TO_SLOT(dev, ether_crc(ETH_ALEN, dmi->dmi_addr));
+               reg = EMAC_XAHT_SLOT_TO_REG(dev, slot);
+               mask = EMAC_XAHT_SLOT_TO_MASK(dev, slot);
+
+               gaht_temp[reg] |= mask;
        }
-       out_be32(&p->gaht1, gaht[0]);
-       out_be32(&p->gaht2, gaht[1]);
-       out_be32(&p->gaht3, gaht[2]);
-       out_be32(&p->gaht4, gaht[3]);
+
+       for (i = 0; i < regs; i++)
+               out_be32(gaht_base + i, gaht_temp[i]);
 }
 
 static inline u32 emac_iff2rmr(struct net_device *ndev)
@@ -398,7 +404,8 @@ static inline u32 emac_iff2rmr(struct net_device *ndev)
 
        if (ndev->flags & IFF_PROMISC)
                r |= EMAC_RMR_PME;
-       else if (ndev->flags & IFF_ALLMULTI || ndev->mc_count > 32)
+       else if (ndev->flags & IFF_ALLMULTI ||
+                        (ndev->mc_count > EMAC_XAHT_SLOTS(dev)))
                r |= EMAC_RMR_PMME;
        else if (ndev->mc_count > 0)
                r |= EMAC_RMR_MAE;
@@ -542,7 +549,7 @@ static int emac_configure(struct emac_instance *dev)
                        /* Put some arbitrary OUI, Manuf & Rev IDs so we can
                         * identify this GPCS PHY later.
                         */
-                       out_be32(&p->ipcr, 0xdeadbeef);
+                       out_be32(&p->u1.emac4.ipcr, 0xdeadbeef);
                } else
                        mr1 |= EMAC_MR1_MF_1000;
 
@@ -2015,10 +2022,10 @@ static int emac_get_regs_len(struct emac_instance *dev)
 {
        if (emac_has_feature(dev, EMAC_FTR_EMAC4))
                return sizeof(struct emac_ethtool_regs_subhdr) +
-                       EMAC4_ETHTOOL_REGS_SIZE;
+                       EMAC4_ETHTOOL_REGS_SIZE(dev);
        else
                return sizeof(struct emac_ethtool_regs_subhdr) +
-                       EMAC_ETHTOOL_REGS_SIZE;
+                       EMAC_ETHTOOL_REGS_SIZE(dev);
 }
 
 static int emac_ethtool_get_regs_len(struct net_device *ndev)
@@ -2045,12 +2052,12 @@ static void *emac_dump_regs(struct emac_instance *dev, void *buf)
        hdr->index = dev->cell_index;
        if (emac_has_feature(dev, EMAC_FTR_EMAC4)) {
                hdr->version = EMAC4_ETHTOOL_REGS_VER;
-               memcpy_fromio(hdr + 1, dev->emacp, EMAC4_ETHTOOL_REGS_SIZE);
-               return ((void *)(hdr + 1) + EMAC4_ETHTOOL_REGS_SIZE);
+               memcpy_fromio(hdr + 1, dev->emacp, EMAC4_ETHTOOL_REGS_SIZE(dev));
+               return ((void *)(hdr + 1) + EMAC4_ETHTOOL_REGS_SIZE(dev));
        } else {
                hdr->version = EMAC_ETHTOOL_REGS_VER;
-               memcpy_fromio(hdr + 1, dev->emacp, EMAC_ETHTOOL_REGS_SIZE);
-               return ((void *)(hdr + 1) + EMAC_ETHTOOL_REGS_SIZE);
+               memcpy_fromio(hdr + 1, dev->emacp, EMAC_ETHTOOL_REGS_SIZE(dev));
+               return ((void *)(hdr + 1) + EMAC_ETHTOOL_REGS_SIZE(dev));
        }
 }
 
@@ -2540,7 +2547,9 @@ static int __devinit emac_init_config(struct emac_instance *dev)
        }
 
        /* Check EMAC version */
-       if (of_device_is_compatible(np, "ibm,emac4")) {
+       if (of_device_is_compatible(np, "ibm,emac4sync")) {
+               dev->features |= (EMAC_FTR_EMAC4 | EMAC_FTR_EMAC4SYNC);
+       } else if (of_device_is_compatible(np, "ibm,emac4")) {
                dev->features |= EMAC_FTR_EMAC4;
                if (of_device_is_compatible(np, "ibm,emac-440gx"))
                        dev->features |= EMAC_FTR_440GX_PHY_CLK_FIX;
@@ -2601,6 +2610,15 @@ static int __devinit emac_init_config(struct emac_instance *dev)
        }
        memcpy(dev->ndev->dev_addr, p, 6);
 
+       /* IAHT and GAHT filter parameterization */
+       if (emac_has_feature(dev, EMAC_FTR_EMAC4SYNC)) {
+               dev->xaht_slots_shift = EMAC4SYNC_XAHT_SLOTS_SHIFT;
+               dev->xaht_width_shift = EMAC4SYNC_XAHT_WIDTH_SHIFT;
+       } else {
+               dev->xaht_slots_shift = EMAC4_XAHT_SLOTS_SHIFT;
+               dev->xaht_width_shift = EMAC4_XAHT_WIDTH_SHIFT;
+       }
+
        DBG(dev, "features     : 0x%08x / 0x%08x\n", dev->features, EMAC_FTRS_POSSIBLE);
        DBG(dev, "tx_fifo_size : %d (%d gige)\n", dev->tx_fifo_size, dev->tx_fifo_size_gige);
        DBG(dev, "rx_fifo_size : %d (%d gige)\n", dev->rx_fifo_size, dev->rx_fifo_size_gige);
@@ -2672,7 +2690,8 @@ static int __devinit emac_probe(struct of_device *ofdev,
                goto err_irq_unmap;
        }
        // TODO : request_mem_region
-       dev->emacp = ioremap(dev->rsrc_regs.start, sizeof(struct emac_regs));
+       dev->emacp = ioremap(dev->rsrc_regs.start,
+                            dev->rsrc_regs.end - dev->rsrc_regs.start + 1);
        if (dev->emacp == NULL) {
                printk(KERN_ERR "%s: Can't map device registers!\n",
                       np->full_name);
@@ -2884,6 +2903,10 @@ static struct of_device_id emac_match[] =
                .type           = "network",
                .compatible     = "ibm,emac4",
        },
+       {
+               .type           = "network",
+               .compatible     = "ibm,emac4sync",
+       },
        {},
 };
 
index 223090466760c1bf0fc3786b178939ae9e8b583e..6545e69d12c31425d75413535a286ab19b804119 100644 (file)
@@ -235,6 +235,10 @@ struct emac_instance {
        u32                             fifo_entry_size;
        u32                             mal_burst_size; /* move to MAL ? */
 
+       /* IAHT and GAHT filter parameterization */
+       u32                             xaht_slots_shift;
+       u32                             xaht_width_shift;
+
        /* Descriptor management
         */
        struct mal_descriptor           *tx_desc;
@@ -309,6 +313,10 @@ struct emac_instance {
  * Set if we need phy clock workaround for 440ep or 440gr
  */
 #define EMAC_FTR_440EP_PHY_CLK_FIX     0x00000100
+/*
+ * The 405EX and 460EX contain the EMAC4SYNC core
+ */
+#define EMAC_FTR_EMAC4SYNC             0x00000200
 
 
 /* Right now, we don't quite handle the always/possible masks on the
@@ -320,7 +328,8 @@ enum {
 
        EMAC_FTRS_POSSIBLE      =
 #ifdef CONFIG_IBM_NEW_EMAC_EMAC4
-           EMAC_FTR_EMAC4 | EMAC_FTR_HAS_NEW_STACR |
+           EMAC_FTR_EMAC4      | EMAC_FTR_EMAC4SYNC    |
+           EMAC_FTR_HAS_NEW_STACR      |
            EMAC_FTR_STACR_OC_INVERT | EMAC_FTR_440GX_PHY_CLK_FIX |
 #endif
 #ifdef CONFIG_IBM_NEW_EMAC_TAH
@@ -342,6 +351,71 @@ static inline int emac_has_feature(struct emac_instance *dev,
               (EMAC_FTRS_POSSIBLE & dev->features & feature);
 }
 
+/*
+ * Various instances of the EMAC core have varying 1) number of
+ * address match slots, 2) width of the registers for handling address
+ * match slots, 3) number of registers for handling address match
+ * slots and 4) base offset for those registers.
+ *
+ * These macros and inlines handle these differences based on
+ * parameters supplied by the device structure which are, in turn,
+ * initialized based on the "compatible" entry in the device tree.
+ */
+
+#define        EMAC4_XAHT_SLOTS_SHIFT          6
+#define        EMAC4_XAHT_WIDTH_SHIFT          4
+
+#define        EMAC4SYNC_XAHT_SLOTS_SHIFT      8
+#define        EMAC4SYNC_XAHT_WIDTH_SHIFT      5
+
+#define        EMAC_XAHT_SLOTS(dev)            (1 << (dev)->xaht_slots_shift)
+#define        EMAC_XAHT_WIDTH(dev)            (1 << (dev)->xaht_width_shift)
+#define        EMAC_XAHT_REGS(dev)             (1 << ((dev)->xaht_slots_shift - \
+                                              (dev)->xaht_width_shift))
+
+#define        EMAC_XAHT_CRC_TO_SLOT(dev, crc)                 \
+       ((EMAC_XAHT_SLOTS(dev) - 1) -                   \
+        ((crc) >> ((sizeof (u32) * BITS_PER_BYTE) -    \
+                   (dev)->xaht_slots_shift)))
+
+#define        EMAC_XAHT_SLOT_TO_REG(dev, slot)                \
+       ((slot) >> (dev)->xaht_width_shift)
+
+#define        EMAC_XAHT_SLOT_TO_MASK(dev, slot)               \
+       ((u32)(1 << (EMAC_XAHT_WIDTH(dev) - 1)) >>      \
+        ((slot) & (u32)(EMAC_XAHT_WIDTH(dev) - 1)))
+
+static inline u32 *emac_xaht_base(struct emac_instance *dev)
+{
+       struct emac_regs __iomem *p = dev->emacp;
+       int offset;
+
+       /* The first IAHT entry always is the base of the block of
+        * IAHT and GAHT registers.
+        */
+       if (emac_has_feature(dev, EMAC_FTR_EMAC4SYNC))
+               offset = offsetof(struct emac_regs, u1.emac4sync.iaht1);
+       else
+               offset = offsetof(struct emac_regs, u0.emac4.iaht1);
+
+       return ((u32 *)((ptrdiff_t)p + offset));
+}
+
+static inline u32 *emac_gaht_base(struct emac_instance *dev)
+{
+       /* GAHT registers always come after an identical number of
+        * IAHT registers.
+        */
+       return (emac_xaht_base(dev) + EMAC_XAHT_REGS(dev));
+}
+
+static inline u32 *emac_iaht_base(struct emac_instance *dev)
+{
+       /* IAHT registers always come before an identical number of
+        * GAHT registers.
+        */
+       return (emac_xaht_base(dev));
+}
 
 /* Ethtool get_regs complex data.
  * We want to get not just EMAC registers, but also MAL, ZMII, RGMII, TAH
@@ -366,4 +440,11 @@ struct emac_ethtool_regs_subhdr {
        u32 index;
 };
 
+#define EMAC_ETHTOOL_REGS_VER          0
+#define EMAC_ETHTOOL_REGS_SIZE(dev)    ((dev)->rsrc_regs.end - \
+                                        (dev)->rsrc_regs.start + 1)
+#define EMAC4_ETHTOOL_REGS_VER         1
+#define EMAC4_ETHTOOL_REGS_SIZE(dev)   ((dev)->rsrc_regs.end - \
+                                        (dev)->rsrc_regs.start + 1)
+
 #endif /* __IBM_NEWEMAC_CORE_H */
index 86b756a30784f844ffd48868edfe5a9161d01d2a..775c850a425a311e9341718fa85b302641fb942b 100644 (file)
@@ -67,29 +67,55 @@ static void emac_desc_dump(struct emac_instance *p)
 static void emac_mac_dump(struct emac_instance *dev)
 {
        struct emac_regs __iomem *p = dev->emacp;
+       const int xaht_regs = EMAC_XAHT_REGS(dev);
+       u32 *gaht_base = emac_gaht_base(dev);
+       u32 *iaht_base = emac_iaht_base(dev);
+       int emac4sync = emac_has_feature(dev, EMAC_FTR_EMAC4SYNC);
+       int n;
 
        printk("** EMAC %s registers **\n"
               "MR0 = 0x%08x MR1 = 0x%08x TMR0 = 0x%08x TMR1 = 0x%08x\n"
               "RMR = 0x%08x ISR = 0x%08x ISER = 0x%08x\n"
-              "IAR = %04x%08x VTPID = 0x%04x VTCI = 0x%04x\n"
-              "IAHT: 0x%04x 0x%04x 0x%04x 0x%04x "
-              "GAHT: 0x%04x 0x%04x 0x%04x 0x%04x\n"
-              "LSA = %04x%08x IPGVR = 0x%04x\n"
-              "STACR = 0x%08x TRTR = 0x%08x RWMR = 0x%08x\n"
-              "OCTX = 0x%08x OCRX = 0x%08x IPCR = 0x%08x\n",
+              "IAR = %04x%08x VTPID = 0x%04x VTCI = 0x%04x\n",
               dev->ofdev->node->full_name, in_be32(&p->mr0), in_be32(&p->mr1),
               in_be32(&p->tmr0), in_be32(&p->tmr1),
               in_be32(&p->rmr), in_be32(&p->isr), in_be32(&p->iser),
               in_be32(&p->iahr), in_be32(&p->ialr), in_be32(&p->vtpid),
-              in_be32(&p->vtci),
-              in_be32(&p->iaht1), in_be32(&p->iaht2), in_be32(&p->iaht3),
-              in_be32(&p->iaht4),
-              in_be32(&p->gaht1), in_be32(&p->gaht2), in_be32(&p->gaht3),
-              in_be32(&p->gaht4),
+              in_be32(&p->vtci)
+              );
+
+       if (emac4sync)
+               printk("MAR = %04x%08x MMAR = %04x%08x\n",
+                      in_be32(&p->u0.emac4sync.mahr),
+                      in_be32(&p->u0.emac4sync.malr),
+                      in_be32(&p->u0.emac4sync.mmahr),
+                      in_be32(&p->u0.emac4sync.mmalr)
+                      );
+
+       for (n = 0; n < xaht_regs; n++)
+               printk("IAHT%02d = 0x%08x\n", n + 1, in_be32(iaht_base + n));
+
+       for (n = 0; n < xaht_regs; n++)
+               printk("GAHT%02d = 0x%08x\n", n + 1, in_be32(gaht_base + n));
+
+       printk("LSA = %04x%08x IPGVR = 0x%04x\n"
+              "STACR = 0x%08x TRTR = 0x%08x RWMR = 0x%08x\n"
+              "OCTX = 0x%08x OCRX = 0x%08x\n",
               in_be32(&p->lsah), in_be32(&p->lsal), in_be32(&p->ipgvr),
               in_be32(&p->stacr), in_be32(&p->trtr), in_be32(&p->rwmr),
-              in_be32(&p->octx), in_be32(&p->ocrx), in_be32(&p->ipcr)
-           );
+              in_be32(&p->octx), in_be32(&p->ocrx)
+              );
+
+       if (!emac4sync) {
+               printk("IPCR = 0x%08x\n",
+                      in_be32(&p->u1.emac4.ipcr)
+                      );
+       } else {
+               printk("REVID = 0x%08x TPC = 0x%08x\n",
+                      in_be32(&p->u1.emac4sync.revid),
+                      in_be32(&p->u1.emac4sync.tpc)
+                      );
+       }
 
        emac_desc_dump(dev);
 }
index 91cb096ab4059e4d6593db85b830fb4d85dcb276..0afc2cf5c52b94ba52d3bf9c2669b90f1a40d7c1 100644 (file)
 
 #include <linux/types.h>
 
-/* EMAC registers              Write Access rules */
+/* EMAC registers                      Write Access rules */
 struct emac_regs {
-       u32 mr0;                /* special      */
-       u32 mr1;                /* Reset        */
-       u32 tmr0;               /* special      */
-       u32 tmr1;               /* special      */
-       u32 rmr;                /* Reset        */
-       u32 isr;                /* Always       */
-       u32 iser;               /* Reset        */
-       u32 iahr;               /* Reset, R, T  */
-       u32 ialr;               /* Reset, R, T  */
-       u32 vtpid;              /* Reset, R, T  */
-       u32 vtci;               /* Reset, R, T  */
-       u32 ptr;                /* Reset,    T  */
-       u32 iaht1;              /* Reset, R     */
-       u32 iaht2;              /* Reset, R     */
-       u32 iaht3;              /* Reset, R     */
-       u32 iaht4;              /* Reset, R     */
-       u32 gaht1;              /* Reset, R     */
-       u32 gaht2;              /* Reset, R     */
-       u32 gaht3;              /* Reset, R     */
-       u32 gaht4;              /* Reset, R     */
+       /* Common registers across all EMAC implementations. */
+       u32 mr0;                        /* Special      */
+       u32 mr1;                        /* Reset        */
+       u32 tmr0;                       /* Special      */
+       u32 tmr1;                       /* Special      */
+       u32 rmr;                        /* Reset        */
+       u32 isr;                        /* Always       */
+       u32 iser;                       /* Reset        */
+       u32 iahr;                       /* Reset, R, T  */
+       u32 ialr;                       /* Reset, R, T  */
+       u32 vtpid;                      /* Reset, R, T  */
+       u32 vtci;                       /* Reset, R, T  */
+       u32 ptr;                        /* Reset,    T  */
+       union {
+               /* Registers unique to EMAC4 implementations */
+               struct {
+                       u32 iaht1;      /* Reset, R     */
+                       u32 iaht2;      /* Reset, R     */
+                       u32 iaht3;      /* Reset, R     */
+                       u32 iaht4;      /* Reset, R     */
+                       u32 gaht1;      /* Reset, R     */
+                       u32 gaht2;      /* Reset, R     */
+                       u32 gaht3;      /* Reset, R     */
+                       u32 gaht4;      /* Reset, R     */
+               } emac4;
+               /* Registers unique to EMAC4SYNC implementations */
+               struct {
+                       u32 mahr;       /* Reset, R, T  */
+                       u32 malr;       /* Reset, R, T  */
+                       u32 mmahr;      /* Reset, R, T  */
+                       u32 mmalr;      /* Reset, R, T  */
+                       u32 rsvd0[4];
+               } emac4sync;
+       } u0;
+       /* Common registers across all EMAC implementations. */
        u32 lsah;
        u32 lsal;
-       u32 ipgvr;              /* Reset,    T  */
-       u32 stacr;              /* special      */
-       u32 trtr;               /* special      */
-       u32 rwmr;               /* Reset        */
+       u32 ipgvr;                      /* Reset,    T  */
+       u32 stacr;                      /* Special      */
+       u32 trtr;                       /* Special      */
+       u32 rwmr;                       /* Reset        */
        u32 octx;
        u32 ocrx;
-       u32 ipcr;
+       union {
+               /* Registers unique to EMAC4 implementations */
+               struct {
+                       u32 ipcr;
+               } emac4;
+               /* Registers unique to EMAC4SYNC implementations */
+               struct {
+                       u32 rsvd1;
+                       u32 revid;
+                       u32 rsvd2[2];
+                       u32 iaht1;      /* Reset, R     */
+                       u32 iaht2;      /* Reset, R     */
+                       u32 iaht3;      /* Reset, R     */
+                       u32 iaht4;      /* Reset, R     */
+                       u32 iaht5;      /* Reset, R     */
+                       u32 iaht6;      /* Reset, R     */
+                       u32 iaht7;      /* Reset, R     */
+                       u32 iaht8;      /* Reset, R     */
+                       u32 gaht1;      /* Reset, R     */
+                       u32 gaht2;      /* Reset, R     */
+                       u32 gaht3;      /* Reset, R     */
+                       u32 gaht4;      /* Reset, R     */
+                       u32 gaht5;      /* Reset, R     */
+                       u32 gaht6;      /* Reset, R     */
+                       u32 gaht7;      /* Reset, R     */
+                       u32 gaht8;      /* Reset, R     */
+                       u32 tpc;        /* Reset, T     */
+               } emac4sync;
+       } u1;
 };
 
 /*
@@ -73,12 +116,6 @@ struct emac_regs {
 #define PHY_MODE_RTBI  7
 #define PHY_MODE_SGMII 8
 
-
-#define EMAC_ETHTOOL_REGS_VER          0
-#define EMAC_ETHTOOL_REGS_SIZE         (sizeof(struct emac_regs) - sizeof(u32))
-#define EMAC4_ETHTOOL_REGS_VER         1
-#define EMAC4_ETHTOOL_REGS_SIZE                sizeof(struct emac_regs)
-
 /* EMACx_MR0 */
 #define EMAC_MR0_RXI                   0x80000000
 #define EMAC_MR0_TXI                   0x40000000