diff options
author | Lennert Buytenhek <buytenh@wantstofly.org> | 2008-04-23 19:29:59 -0400 |
---|---|---|
committer | Dale Farnsworth <dale@farnsworth.org> | 2008-04-29 00:17:07 -0400 |
commit | ce4e2e4558903ef92edf1ab4e09b0b338a09fd61 (patch) | |
tree | dbfd7901022f9761214469749d19b07ba1d441b1 | |
parent | 240e4419e0cfcba737883b637ec2bdcc071ea03d (diff) |
mv643xx_eth: inter-mv643xx SMI port sharing
There exist chips with up to four mv643xx_eth silicon blocks but
only one external SMI (MII management) interface -- the SMI logic
of the first block is shared by all the blocks.
Handle this by allowing a per-port override of which
mv643xx_eth_shared's SMI registers (and spinlock) to use.
Signed-off-by: Lennert Buytenhek <buytenh@marvell.com>
Acked-by: Nicolas Pitre <nico@marvell.com>
Signed-off-by: Dale Farnsworth <dale@farnsworth.org>
-rw-r--r-- | drivers/net/mv643xx_eth.c | 38 | ||||
-rw-r--r-- | include/linux/mv643xx_eth.h | 2 |
2 files changed, 24 insertions, 16 deletions
diff --git a/drivers/net/mv643xx_eth.c b/drivers/net/mv643xx_eth.c index 8bd41e4e88a9..b7915cdcc6a5 100644 --- a/drivers/net/mv643xx_eth.c +++ b/drivers/net/mv643xx_eth.c | |||
@@ -527,6 +527,8 @@ struct mv643xx_private { | |||
527 | struct mv643xx_shared_private *shared; | 527 | struct mv643xx_shared_private *shared; |
528 | int port_num; /* User Ethernet port number */ | 528 | int port_num; /* User Ethernet port number */ |
529 | 529 | ||
530 | struct mv643xx_shared_private *shared_smi; | ||
531 | |||
530 | u32 rx_sram_addr; /* Base address of rx sram area */ | 532 | u32 rx_sram_addr; /* Base address of rx sram area */ |
531 | u32 rx_sram_size; /* Size of rx sram area */ | 533 | u32 rx_sram_size; /* Size of rx sram area */ |
532 | u32 tx_sram_addr; /* Base address of tx sram area */ | 534 | u32 tx_sram_addr; /* Base address of tx sram area */ |
@@ -1898,6 +1900,10 @@ static int mv643xx_eth_probe(struct platform_device *pdev) | |||
1898 | if (mp->shared->win_protect) | 1900 | if (mp->shared->win_protect) |
1899 | wrl(mp, WINDOW_PROTECT(port_num), mp->shared->win_protect); | 1901 | wrl(mp, WINDOW_PROTECT(port_num), mp->shared->win_protect); |
1900 | 1902 | ||
1903 | mp->shared_smi = mp->shared; | ||
1904 | if (pd->shared_smi != NULL) | ||
1905 | mp->shared_smi = platform_get_drvdata(pd->shared_smi); | ||
1906 | |||
1901 | /* set default config values */ | 1907 | /* set default config values */ |
1902 | eth_port_uc_addr_get(mp, dev->dev_addr); | 1908 | eth_port_uc_addr_get(mp, dev->dev_addr); |
1903 | mp->rx_ring_size = PORT_DEFAULT_RECEIVE_QUEUE_SIZE; | 1909 | mp->rx_ring_size = PORT_DEFAULT_RECEIVE_QUEUE_SIZE; |
@@ -2986,15 +2992,16 @@ static void eth_port_reset(struct mv643xx_private *mp) | |||
2986 | static void eth_port_read_smi_reg(struct mv643xx_private *mp, | 2992 | static void eth_port_read_smi_reg(struct mv643xx_private *mp, |
2987 | unsigned int phy_reg, unsigned int *value) | 2993 | unsigned int phy_reg, unsigned int *value) |
2988 | { | 2994 | { |
2995 | void __iomem *smi_reg = mp->shared_smi->eth_base + SMI_REG; | ||
2989 | int phy_addr = ethernet_phy_get(mp); | 2996 | int phy_addr = ethernet_phy_get(mp); |
2990 | unsigned long flags; | 2997 | unsigned long flags; |
2991 | int i; | 2998 | int i; |
2992 | 2999 | ||
2993 | /* the SMI register is a shared resource */ | 3000 | /* the SMI register is a shared resource */ |
2994 | spin_lock_irqsave(&mp->shared->phy_lock, flags); | 3001 | spin_lock_irqsave(&mp->shared_smi->phy_lock, flags); |
2995 | 3002 | ||
2996 | /* wait for the SMI register to become available */ | 3003 | /* wait for the SMI register to become available */ |
2997 | for (i = 0; rdl(mp, SMI_REG) & ETH_SMI_BUSY; i++) { | 3004 | for (i = 0; readl(smi_reg) & ETH_SMI_BUSY; i++) { |
2998 | if (i == PHY_WAIT_ITERATIONS) { | 3005 | if (i == PHY_WAIT_ITERATIONS) { |
2999 | printk("%s: PHY busy timeout\n", mp->dev->name); | 3006 | printk("%s: PHY busy timeout\n", mp->dev->name); |
3000 | goto out; | 3007 | goto out; |
@@ -3002,11 +3009,11 @@ static void eth_port_read_smi_reg(struct mv643xx_private *mp, | |||
3002 | udelay(PHY_WAIT_MICRO_SECONDS); | 3009 | udelay(PHY_WAIT_MICRO_SECONDS); |
3003 | } | 3010 | } |
3004 | 3011 | ||
3005 | wrl(mp, SMI_REG, | 3012 | writel((phy_addr << 16) | (phy_reg << 21) | ETH_SMI_OPCODE_READ, |
3006 | (phy_addr << 16) | (phy_reg << 21) | ETH_SMI_OPCODE_READ); | 3013 | smi_reg); |
3007 | 3014 | ||
3008 | /* now wait for the data to be valid */ | 3015 | /* now wait for the data to be valid */ |
3009 | for (i = 0; !(rdl(mp, SMI_REG) & ETH_SMI_READ_VALID); i++) { | 3016 | for (i = 0; !(readl(smi_reg) & ETH_SMI_READ_VALID); i++) { |
3010 | if (i == PHY_WAIT_ITERATIONS) { | 3017 | if (i == PHY_WAIT_ITERATIONS) { |
3011 | printk("%s: PHY read timeout\n", mp->dev->name); | 3018 | printk("%s: PHY read timeout\n", mp->dev->name); |
3012 | goto out; | 3019 | goto out; |
@@ -3014,9 +3021,9 @@ static void eth_port_read_smi_reg(struct mv643xx_private *mp, | |||
3014 | udelay(PHY_WAIT_MICRO_SECONDS); | 3021 | udelay(PHY_WAIT_MICRO_SECONDS); |
3015 | } | 3022 | } |
3016 | 3023 | ||
3017 | *value = rdl(mp, SMI_REG) & 0xffff; | 3024 | *value = readl(smi_reg) & 0xffff; |
3018 | out: | 3025 | out: |
3019 | spin_unlock_irqrestore(&mp->shared->phy_lock, flags); | 3026 | spin_unlock_irqrestore(&mp->shared_smi->phy_lock, flags); |
3020 | } | 3027 | } |
3021 | 3028 | ||
3022 | /* | 3029 | /* |
@@ -3042,17 +3049,16 @@ out: | |||
3042 | static void eth_port_write_smi_reg(struct mv643xx_private *mp, | 3049 | static void eth_port_write_smi_reg(struct mv643xx_private *mp, |
3043 | unsigned int phy_reg, unsigned int value) | 3050 | unsigned int phy_reg, unsigned int value) |
3044 | { | 3051 | { |
3045 | int phy_addr; | 3052 | void __iomem *smi_reg = mp->shared_smi->eth_base + SMI_REG; |
3046 | int i; | 3053 | int phy_addr = ethernet_phy_get(mp); |
3047 | unsigned long flags; | 3054 | unsigned long flags; |
3048 | 3055 | int i; | |
3049 | phy_addr = ethernet_phy_get(mp); | ||
3050 | 3056 | ||
3051 | /* the SMI register is a shared resource */ | 3057 | /* the SMI register is a shared resource */ |
3052 | spin_lock_irqsave(&mp->shared->phy_lock, flags); | 3058 | spin_lock_irqsave(&mp->shared_smi->phy_lock, flags); |
3053 | 3059 | ||
3054 | /* wait for the SMI register to become available */ | 3060 | /* wait for the SMI register to become available */ |
3055 | for (i = 0; rdl(mp, SMI_REG) & ETH_SMI_BUSY; i++) { | 3061 | for (i = 0; readl(smi_reg) & ETH_SMI_BUSY; i++) { |
3056 | if (i == PHY_WAIT_ITERATIONS) { | 3062 | if (i == PHY_WAIT_ITERATIONS) { |
3057 | printk("%s: PHY busy timeout\n", mp->dev->name); | 3063 | printk("%s: PHY busy timeout\n", mp->dev->name); |
3058 | goto out; | 3064 | goto out; |
@@ -3060,10 +3066,10 @@ static void eth_port_write_smi_reg(struct mv643xx_private *mp, | |||
3060 | udelay(PHY_WAIT_MICRO_SECONDS); | 3066 | udelay(PHY_WAIT_MICRO_SECONDS); |
3061 | } | 3067 | } |
3062 | 3068 | ||
3063 | wrl(mp, SMI_REG, (phy_addr << 16) | (phy_reg << 21) | | 3069 | writel((phy_addr << 16) | (phy_reg << 21) | |
3064 | ETH_SMI_OPCODE_WRITE | (value & 0xffff)); | 3070 | ETH_SMI_OPCODE_WRITE | (value & 0xffff), smi_reg); |
3065 | out: | 3071 | out: |
3066 | spin_unlock_irqrestore(&mp->shared->phy_lock, flags); | 3072 | spin_unlock_irqrestore(&mp->shared_smi->phy_lock, flags); |
3067 | } | 3073 | } |
3068 | 3074 | ||
3069 | /* | 3075 | /* |
diff --git a/include/linux/mv643xx_eth.h b/include/linux/mv643xx_eth.h index 66dc9571922a..a15cdd4a8e58 100644 --- a/include/linux/mv643xx_eth.h +++ b/include/linux/mv643xx_eth.h | |||
@@ -24,6 +24,8 @@ struct mv643xx_eth_platform_data { | |||
24 | struct platform_device *shared; | 24 | struct platform_device *shared; |
25 | int port_number; | 25 | int port_number; |
26 | 26 | ||
27 | struct platform_device *shared_smi; | ||
28 | |||
27 | u16 force_phy_addr; /* force override if phy_addr == 0 */ | 29 | u16 force_phy_addr; /* force override if phy_addr == 0 */ |
28 | u16 phy_addr; | 30 | u16 phy_addr; |
29 | 31 | ||