diff options
author | Jeff Garzik <jeff@garzik.org> | 2008-05-06 12:22:03 -0400 |
---|---|---|
committer | Jeff Garzik <jgarzik@redhat.com> | 2008-05-06 12:22:03 -0400 |
commit | 54c852a2d61bb15d9b979410c2260edfb23d448c (patch) | |
tree | 7a6ba9d1743b01090b85611cea9dd79ec2950487 /drivers/net | |
parent | 7ab267d4ecdad3032d6bb31619a2744fc2074b59 (diff) | |
parent | ce4e2e4558903ef92edf1ab4e09b0b338a09fd61 (diff) |
Merge branch 'for-2.6.26' of git://git.farnsworth.org/dale/linux-2.6-mv643xx_eth into upstream
Diffstat (limited to 'drivers/net')
-rw-r--r-- | drivers/net/mv643xx_eth.c | 160 |
1 files changed, 123 insertions, 37 deletions
diff --git a/drivers/net/mv643xx_eth.c b/drivers/net/mv643xx_eth.c index 381b36e5f64c..b7915cdcc6a5 100644 --- a/drivers/net/mv643xx_eth.c +++ b/drivers/net/mv643xx_eth.c | |||
@@ -91,6 +91,11 @@ | |||
91 | */ | 91 | */ |
92 | #define PHY_ADDR_REG 0x0000 | 92 | #define PHY_ADDR_REG 0x0000 |
93 | #define SMI_REG 0x0004 | 93 | #define SMI_REG 0x0004 |
94 | #define WINDOW_BASE(i) (0x0200 + ((i) << 3)) | ||
95 | #define WINDOW_SIZE(i) (0x0204 + ((i) << 3)) | ||
96 | #define WINDOW_REMAP_HIGH(i) (0x0280 + ((i) << 2)) | ||
97 | #define WINDOW_BAR_ENABLE 0x0290 | ||
98 | #define WINDOW_PROTECT(i) (0x0294 + ((i) << 4)) | ||
94 | 99 | ||
95 | /* | 100 | /* |
96 | * Per-port registers. | 101 | * Per-port registers. |
@@ -507,9 +512,23 @@ struct mv643xx_mib_counters { | |||
507 | u32 late_collision; | 512 | u32 late_collision; |
508 | }; | 513 | }; |
509 | 514 | ||
515 | struct mv643xx_shared_private { | ||
516 | void __iomem *eth_base; | ||
517 | |||
518 | /* used to protect SMI_REG, which is shared across ports */ | ||
519 | spinlock_t phy_lock; | ||
520 | |||
521 | u32 win_protect; | ||
522 | |||
523 | unsigned int t_clk; | ||
524 | }; | ||
525 | |||
510 | struct mv643xx_private { | 526 | struct mv643xx_private { |
527 | struct mv643xx_shared_private *shared; | ||
511 | int port_num; /* User Ethernet port number */ | 528 | int port_num; /* User Ethernet port number */ |
512 | 529 | ||
530 | struct mv643xx_shared_private *shared_smi; | ||
531 | |||
513 | u32 rx_sram_addr; /* Base address of rx sram area */ | 532 | u32 rx_sram_addr; /* Base address of rx sram area */ |
514 | u32 rx_sram_size; /* Size of rx sram area */ | 533 | u32 rx_sram_size; /* Size of rx sram area */ |
515 | u32 tx_sram_addr; /* Base address of tx sram area */ | 534 | u32 tx_sram_addr; /* Base address of tx sram area */ |
@@ -614,19 +633,14 @@ static const struct ethtool_ops mv643xx_ethtool_ops; | |||
614 | static char mv643xx_driver_name[] = "mv643xx_eth"; | 633 | static char mv643xx_driver_name[] = "mv643xx_eth"; |
615 | static char mv643xx_driver_version[] = "1.0"; | 634 | static char mv643xx_driver_version[] = "1.0"; |
616 | 635 | ||
617 | static void __iomem *mv643xx_eth_base; | ||
618 | |||
619 | /* used to protect SMI_REG, which is shared across ports */ | ||
620 | static DEFINE_SPINLOCK(mv643xx_eth_phy_lock); | ||
621 | |||
622 | static inline u32 rdl(struct mv643xx_private *mp, int offset) | 636 | static inline u32 rdl(struct mv643xx_private *mp, int offset) |
623 | { | 637 | { |
624 | return readl(mv643xx_eth_base + offset); | 638 | return readl(mp->shared->eth_base + offset); |
625 | } | 639 | } |
626 | 640 | ||
627 | static inline void wrl(struct mv643xx_private *mp, int offset, u32 data) | 641 | static inline void wrl(struct mv643xx_private *mp, int offset, u32 data) |
628 | { | 642 | { |
629 | writel(data, mv643xx_eth_base + offset); | 643 | writel(data, mp->shared->eth_base + offset); |
630 | } | 644 | } |
631 | 645 | ||
632 | /* | 646 | /* |
@@ -1119,7 +1133,6 @@ static irqreturn_t mv643xx_eth_int_handler(int irq, void *dev_id) | |||
1119 | * | 1133 | * |
1120 | * INPUT: | 1134 | * INPUT: |
1121 | * struct mv643xx_private *mp Ethernet port | 1135 | * struct mv643xx_private *mp Ethernet port |
1122 | * unsigned int t_clk t_clk of the MV-643xx chip in HZ units | ||
1123 | * unsigned int delay Delay in usec | 1136 | * unsigned int delay Delay in usec |
1124 | * | 1137 | * |
1125 | * OUTPUT: | 1138 | * OUTPUT: |
@@ -1130,10 +1143,10 @@ static irqreturn_t mv643xx_eth_int_handler(int irq, void *dev_id) | |||
1130 | * | 1143 | * |
1131 | */ | 1144 | */ |
1132 | static unsigned int eth_port_set_rx_coal(struct mv643xx_private *mp, | 1145 | static unsigned int eth_port_set_rx_coal(struct mv643xx_private *mp, |
1133 | unsigned int t_clk, unsigned int delay) | 1146 | unsigned int delay) |
1134 | { | 1147 | { |
1135 | unsigned int port_num = mp->port_num; | 1148 | unsigned int port_num = mp->port_num; |
1136 | unsigned int coal = ((t_clk / 1000000) * delay) / 64; | 1149 | unsigned int coal = ((mp->shared->t_clk / 1000000) * delay) / 64; |
1137 | 1150 | ||
1138 | /* Set RX Coalescing mechanism */ | 1151 | /* Set RX Coalescing mechanism */ |
1139 | wrl(mp, SDMA_CONFIG_REG(port_num), | 1152 | wrl(mp, SDMA_CONFIG_REG(port_num), |
@@ -1158,7 +1171,6 @@ static unsigned int eth_port_set_rx_coal(struct mv643xx_private *mp, | |||
1158 | * | 1171 | * |
1159 | * INPUT: | 1172 | * INPUT: |
1160 | * struct mv643xx_private *mp Ethernet port | 1173 | * struct mv643xx_private *mp Ethernet port |
1161 | * unsigned int t_clk t_clk of the MV-643xx chip in HZ units | ||
1162 | * unsigned int delay Delay in uSeconds | 1174 | * unsigned int delay Delay in uSeconds |
1163 | * | 1175 | * |
1164 | * OUTPUT: | 1176 | * OUTPUT: |
@@ -1169,9 +1181,9 @@ static unsigned int eth_port_set_rx_coal(struct mv643xx_private *mp, | |||
1169 | * | 1181 | * |
1170 | */ | 1182 | */ |
1171 | static unsigned int eth_port_set_tx_coal(struct mv643xx_private *mp, | 1183 | static unsigned int eth_port_set_tx_coal(struct mv643xx_private *mp, |
1172 | unsigned int t_clk, unsigned int delay) | 1184 | unsigned int delay) |
1173 | { | 1185 | { |
1174 | unsigned int coal = ((t_clk / 1000000) * delay) / 64; | 1186 | unsigned int coal = ((mp->shared->t_clk / 1000000) * delay) / 64; |
1175 | 1187 | ||
1176 | /* Set TX Coalescing mechanism */ | 1188 | /* Set TX Coalescing mechanism */ |
1177 | wrl(mp, TX_FIFO_URGENT_THRESHOLD_REG(mp->port_num), coal << 4); | 1189 | wrl(mp, TX_FIFO_URGENT_THRESHOLD_REG(mp->port_num), coal << 4); |
@@ -1413,11 +1425,11 @@ static int mv643xx_eth_open(struct net_device *dev) | |||
1413 | 1425 | ||
1414 | #ifdef MV643XX_COAL | 1426 | #ifdef MV643XX_COAL |
1415 | mp->rx_int_coal = | 1427 | mp->rx_int_coal = |
1416 | eth_port_set_rx_coal(mp, 133000000, MV643XX_RX_COAL); | 1428 | eth_port_set_rx_coal(mp, MV643XX_RX_COAL); |
1417 | #endif | 1429 | #endif |
1418 | 1430 | ||
1419 | mp->tx_int_coal = | 1431 | mp->tx_int_coal = |
1420 | eth_port_set_tx_coal(mp, 133000000, MV643XX_TX_COAL); | 1432 | eth_port_set_tx_coal(mp, MV643XX_TX_COAL); |
1421 | 1433 | ||
1422 | /* Unmask phy and link status changes interrupts */ | 1434 | /* Unmask phy and link status changes interrupts */ |
1423 | wrl(mp, INTERRUPT_EXTEND_MASK_REG(port_num), ETH_INT_UNMASK_ALL_EXT); | 1435 | wrl(mp, INTERRUPT_EXTEND_MASK_REG(port_num), ETH_INT_UNMASK_ALL_EXT); |
@@ -1827,6 +1839,11 @@ static int mv643xx_eth_probe(struct platform_device *pdev) | |||
1827 | return -ENODEV; | 1839 | return -ENODEV; |
1828 | } | 1840 | } |
1829 | 1841 | ||
1842 | if (pd->shared == NULL) { | ||
1843 | printk(KERN_ERR "No mv643xx_eth_platform_data->shared\n"); | ||
1844 | return -ENODEV; | ||
1845 | } | ||
1846 | |||
1830 | dev = alloc_etherdev(sizeof(struct mv643xx_private)); | 1847 | dev = alloc_etherdev(sizeof(struct mv643xx_private)); |
1831 | if (!dev) | 1848 | if (!dev) |
1832 | return -ENOMEM; | 1849 | return -ENOMEM; |
@@ -1877,8 +1894,16 @@ static int mv643xx_eth_probe(struct platform_device *pdev) | |||
1877 | 1894 | ||
1878 | spin_lock_init(&mp->lock); | 1895 | spin_lock_init(&mp->lock); |
1879 | 1896 | ||
1897 | mp->shared = platform_get_drvdata(pd->shared); | ||
1880 | port_num = mp->port_num = pd->port_number; | 1898 | port_num = mp->port_num = pd->port_number; |
1881 | 1899 | ||
1900 | if (mp->shared->win_protect) | ||
1901 | wrl(mp, WINDOW_PROTECT(port_num), mp->shared->win_protect); | ||
1902 | |||
1903 | mp->shared_smi = mp->shared; | ||
1904 | if (pd->shared_smi != NULL) | ||
1905 | mp->shared_smi = platform_get_drvdata(pd->shared_smi); | ||
1906 | |||
1882 | /* set default config values */ | 1907 | /* set default config values */ |
1883 | eth_port_uc_addr_get(mp, dev->dev_addr); | 1908 | eth_port_uc_addr_get(mp, dev->dev_addr); |
1884 | mp->rx_ring_size = PORT_DEFAULT_RECEIVE_QUEUE_SIZE; | 1909 | mp->rx_ring_size = PORT_DEFAULT_RECEIVE_QUEUE_SIZE; |
@@ -1983,30 +2008,91 @@ static int mv643xx_eth_remove(struct platform_device *pdev) | |||
1983 | return 0; | 2008 | return 0; |
1984 | } | 2009 | } |
1985 | 2010 | ||
2011 | static void mv643xx_eth_conf_mbus_windows(struct mv643xx_shared_private *msp, | ||
2012 | struct mbus_dram_target_info *dram) | ||
2013 | { | ||
2014 | void __iomem *base = msp->eth_base; | ||
2015 | u32 win_enable; | ||
2016 | u32 win_protect; | ||
2017 | int i; | ||
2018 | |||
2019 | for (i = 0; i < 6; i++) { | ||
2020 | writel(0, base + WINDOW_BASE(i)); | ||
2021 | writel(0, base + WINDOW_SIZE(i)); | ||
2022 | if (i < 4) | ||
2023 | writel(0, base + WINDOW_REMAP_HIGH(i)); | ||
2024 | } | ||
2025 | |||
2026 | win_enable = 0x3f; | ||
2027 | win_protect = 0; | ||
2028 | |||
2029 | for (i = 0; i < dram->num_cs; i++) { | ||
2030 | struct mbus_dram_window *cs = dram->cs + i; | ||
2031 | |||
2032 | writel((cs->base & 0xffff0000) | | ||
2033 | (cs->mbus_attr << 8) | | ||
2034 | dram->mbus_dram_target_id, base + WINDOW_BASE(i)); | ||
2035 | writel((cs->size - 1) & 0xffff0000, base + WINDOW_SIZE(i)); | ||
2036 | |||
2037 | win_enable &= ~(1 << i); | ||
2038 | win_protect |= 3 << (2 * i); | ||
2039 | } | ||
2040 | |||
2041 | writel(win_enable, base + WINDOW_BAR_ENABLE); | ||
2042 | msp->win_protect = win_protect; | ||
2043 | } | ||
2044 | |||
1986 | static int mv643xx_eth_shared_probe(struct platform_device *pdev) | 2045 | static int mv643xx_eth_shared_probe(struct platform_device *pdev) |
1987 | { | 2046 | { |
1988 | static int mv643xx_version_printed = 0; | 2047 | static int mv643xx_version_printed = 0; |
2048 | struct mv643xx_eth_shared_platform_data *pd = pdev->dev.platform_data; | ||
2049 | struct mv643xx_shared_private *msp; | ||
1989 | struct resource *res; | 2050 | struct resource *res; |
2051 | int ret; | ||
1990 | 2052 | ||
1991 | if (!mv643xx_version_printed++) | 2053 | if (!mv643xx_version_printed++) |
1992 | printk(KERN_NOTICE "MV-643xx 10/100/1000 Ethernet Driver\n"); | 2054 | printk(KERN_NOTICE "MV-643xx 10/100/1000 Ethernet Driver\n"); |
1993 | 2055 | ||
2056 | ret = -EINVAL; | ||
1994 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 2057 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
1995 | if (res == NULL) | 2058 | if (res == NULL) |
1996 | return -ENODEV; | 2059 | goto out; |
1997 | 2060 | ||
1998 | mv643xx_eth_base = ioremap(res->start, res->end - res->start + 1); | 2061 | ret = -ENOMEM; |
1999 | if (mv643xx_eth_base == NULL) | 2062 | msp = kmalloc(sizeof(*msp), GFP_KERNEL); |
2000 | return -ENOMEM; | 2063 | if (msp == NULL) |
2064 | goto out; | ||
2065 | memset(msp, 0, sizeof(*msp)); | ||
2066 | |||
2067 | msp->eth_base = ioremap(res->start, res->end - res->start + 1); | ||
2068 | if (msp->eth_base == NULL) | ||
2069 | goto out_free; | ||
2070 | |||
2071 | spin_lock_init(&msp->phy_lock); | ||
2072 | msp->t_clk = (pd != NULL && pd->t_clk != 0) ? pd->t_clk : 133000000; | ||
2073 | |||
2074 | platform_set_drvdata(pdev, msp); | ||
2075 | |||
2076 | /* | ||
2077 | * (Re-)program MBUS remapping windows if we are asked to. | ||
2078 | */ | ||
2079 | if (pd != NULL && pd->dram != NULL) | ||
2080 | mv643xx_eth_conf_mbus_windows(msp, pd->dram); | ||
2001 | 2081 | ||
2002 | return 0; | 2082 | return 0; |
2003 | 2083 | ||
2084 | out_free: | ||
2085 | kfree(msp); | ||
2086 | out: | ||
2087 | return ret; | ||
2004 | } | 2088 | } |
2005 | 2089 | ||
2006 | static int mv643xx_eth_shared_remove(struct platform_device *pdev) | 2090 | static int mv643xx_eth_shared_remove(struct platform_device *pdev) |
2007 | { | 2091 | { |
2008 | iounmap(mv643xx_eth_base); | 2092 | struct mv643xx_shared_private *msp = platform_get_drvdata(pdev); |
2009 | mv643xx_eth_base = NULL; | 2093 | |
2094 | iounmap(msp->eth_base); | ||
2095 | kfree(msp); | ||
2010 | 2096 | ||
2011 | return 0; | 2097 | return 0; |
2012 | } | 2098 | } |
@@ -2906,15 +2992,16 @@ static void eth_port_reset(struct mv643xx_private *mp) | |||
2906 | static void eth_port_read_smi_reg(struct mv643xx_private *mp, | 2992 | static void eth_port_read_smi_reg(struct mv643xx_private *mp, |
2907 | unsigned int phy_reg, unsigned int *value) | 2993 | unsigned int phy_reg, unsigned int *value) |
2908 | { | 2994 | { |
2995 | void __iomem *smi_reg = mp->shared_smi->eth_base + SMI_REG; | ||
2909 | int phy_addr = ethernet_phy_get(mp); | 2996 | int phy_addr = ethernet_phy_get(mp); |
2910 | unsigned long flags; | 2997 | unsigned long flags; |
2911 | int i; | 2998 | int i; |
2912 | 2999 | ||
2913 | /* the SMI register is a shared resource */ | 3000 | /* the SMI register is a shared resource */ |
2914 | spin_lock_irqsave(&mv643xx_eth_phy_lock, flags); | 3001 | spin_lock_irqsave(&mp->shared_smi->phy_lock, flags); |
2915 | 3002 | ||
2916 | /* wait for the SMI register to become available */ | 3003 | /* wait for the SMI register to become available */ |
2917 | for (i = 0; rdl(mp, SMI_REG) & ETH_SMI_BUSY; i++) { | 3004 | for (i = 0; readl(smi_reg) & ETH_SMI_BUSY; i++) { |
2918 | if (i == PHY_WAIT_ITERATIONS) { | 3005 | if (i == PHY_WAIT_ITERATIONS) { |
2919 | printk("%s: PHY busy timeout\n", mp->dev->name); | 3006 | printk("%s: PHY busy timeout\n", mp->dev->name); |
2920 | goto out; | 3007 | goto out; |
@@ -2922,11 +3009,11 @@ static void eth_port_read_smi_reg(struct mv643xx_private *mp, | |||
2922 | udelay(PHY_WAIT_MICRO_SECONDS); | 3009 | udelay(PHY_WAIT_MICRO_SECONDS); |
2923 | } | 3010 | } |
2924 | 3011 | ||
2925 | wrl(mp, SMI_REG, | 3012 | writel((phy_addr << 16) | (phy_reg << 21) | ETH_SMI_OPCODE_READ, |
2926 | (phy_addr << 16) | (phy_reg << 21) | ETH_SMI_OPCODE_READ); | 3013 | smi_reg); |
2927 | 3014 | ||
2928 | /* now wait for the data to be valid */ | 3015 | /* now wait for the data to be valid */ |
2929 | for (i = 0; !(rdl(mp, SMI_REG) & ETH_SMI_READ_VALID); i++) { | 3016 | for (i = 0; !(readl(smi_reg) & ETH_SMI_READ_VALID); i++) { |
2930 | if (i == PHY_WAIT_ITERATIONS) { | 3017 | if (i == PHY_WAIT_ITERATIONS) { |
2931 | printk("%s: PHY read timeout\n", mp->dev->name); | 3018 | printk("%s: PHY read timeout\n", mp->dev->name); |
2932 | goto out; | 3019 | goto out; |
@@ -2934,9 +3021,9 @@ static void eth_port_read_smi_reg(struct mv643xx_private *mp, | |||
2934 | udelay(PHY_WAIT_MICRO_SECONDS); | 3021 | udelay(PHY_WAIT_MICRO_SECONDS); |
2935 | } | 3022 | } |
2936 | 3023 | ||
2937 | *value = rdl(mp, SMI_REG) & 0xffff; | 3024 | *value = readl(smi_reg) & 0xffff; |
2938 | out: | 3025 | out: |
2939 | spin_unlock_irqrestore(&mv643xx_eth_phy_lock, flags); | 3026 | spin_unlock_irqrestore(&mp->shared_smi->phy_lock, flags); |
2940 | } | 3027 | } |
2941 | 3028 | ||
2942 | /* | 3029 | /* |
@@ -2962,17 +3049,16 @@ out: | |||
2962 | static void eth_port_write_smi_reg(struct mv643xx_private *mp, | 3049 | static void eth_port_write_smi_reg(struct mv643xx_private *mp, |
2963 | unsigned int phy_reg, unsigned int value) | 3050 | unsigned int phy_reg, unsigned int value) |
2964 | { | 3051 | { |
2965 | int phy_addr; | 3052 | void __iomem *smi_reg = mp->shared_smi->eth_base + SMI_REG; |
2966 | int i; | 3053 | int phy_addr = ethernet_phy_get(mp); |
2967 | unsigned long flags; | 3054 | unsigned long flags; |
2968 | 3055 | int i; | |
2969 | phy_addr = ethernet_phy_get(mp); | ||
2970 | 3056 | ||
2971 | /* the SMI register is a shared resource */ | 3057 | /* the SMI register is a shared resource */ |
2972 | spin_lock_irqsave(&mv643xx_eth_phy_lock, flags); | 3058 | spin_lock_irqsave(&mp->shared_smi->phy_lock, flags); |
2973 | 3059 | ||
2974 | /* wait for the SMI register to become available */ | 3060 | /* wait for the SMI register to become available */ |
2975 | for (i = 0; rdl(mp, SMI_REG) & ETH_SMI_BUSY; i++) { | 3061 | for (i = 0; readl(smi_reg) & ETH_SMI_BUSY; i++) { |
2976 | if (i == PHY_WAIT_ITERATIONS) { | 3062 | if (i == PHY_WAIT_ITERATIONS) { |
2977 | printk("%s: PHY busy timeout\n", mp->dev->name); | 3063 | printk("%s: PHY busy timeout\n", mp->dev->name); |
2978 | goto out; | 3064 | goto out; |
@@ -2980,10 +3066,10 @@ static void eth_port_write_smi_reg(struct mv643xx_private *mp, | |||
2980 | udelay(PHY_WAIT_MICRO_SECONDS); | 3066 | udelay(PHY_WAIT_MICRO_SECONDS); |
2981 | } | 3067 | } |
2982 | 3068 | ||
2983 | wrl(mp, SMI_REG, (phy_addr << 16) | (phy_reg << 21) | | 3069 | writel((phy_addr << 16) | (phy_reg << 21) | |
2984 | ETH_SMI_OPCODE_WRITE | (value & 0xffff)); | 3070 | ETH_SMI_OPCODE_WRITE | (value & 0xffff), smi_reg); |
2985 | out: | 3071 | out: |
2986 | spin_unlock_irqrestore(&mv643xx_eth_phy_lock, flags); | 3072 | spin_unlock_irqrestore(&mp->shared_smi->phy_lock, flags); |
2987 | } | 3073 | } |
2988 | 3074 | ||
2989 | /* | 3075 | /* |