Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

The ixp2000 driver for the enp2611 was developed on a board with three gigabit ports, but some enp2611 models only have two ports (and only one onboard PM3386.) The current driver assumes there are always three ports and so it doesn't work on the two-port version of the board at all.

This patch adds a bit of logic to the enp2611 driver to limit the
number of ports to 2 if the second PM3386 isn't detected.

Signed-off-by: Lennert Buytenhek <buytenh@wantstofly.org>
Signed-off-by: Stephen Hemminger <shemminger@osdl.org>

authored by

Lennert Buytenhek and committed by
Stephen Hemminger
1ea739a5 9be2f7c3

+34 -10
+9 -4
drivers/net/ixp2000/enp2611.c
··· 149 149 int status; 150 150 151 151 dev = nds[i]; 152 + if (dev == NULL) 153 + continue; 152 154 153 155 status = pm3386_is_link_up(i); 154 156 if (status && !netif_carrier_ok(dev)) { ··· 193 191 194 192 static int __init enp2611_init_module(void) 195 193 { 194 + int ports; 196 195 int i; 197 196 198 197 if (!machine_is_enp2611()) ··· 202 199 caleb_reset(); 203 200 pm3386_reset(); 204 201 205 - for (i = 0; i < 3; i++) { 202 + ports = pm3386_port_count(); 203 + for (i = 0; i < ports; i++) { 206 204 nds[i] = ixpdev_alloc(i, sizeof(struct enp2611_ixpdev_priv)); 207 205 if (nds[i] == NULL) { 208 206 while (--i >= 0) ··· 219 215 220 216 ixp2400_msf_init(&enp2611_msf_parameters); 221 217 222 - if (ixpdev_init(3, nds, enp2611_set_port_admin_status)) { 223 - for (i = 0; i < 3; i++) 224 - free_netdev(nds[i]); 218 + if (ixpdev_init(ports, nds, enp2611_set_port_admin_status)) { 219 + for (i = 0; i < ports; i++) 220 + if (nds[i]) 221 + free_netdev(nds[i]); 225 222 return -EINVAL; 226 223 } 227 224
+24 -6
drivers/net/ixp2000/pm3386.c
··· 86 86 pm3386_reg_write(port >> 1, reg, value); 87 87 } 88 88 89 + int pm3386_secondary_present(void) 90 + { 91 + return pm3386_reg_read(1, 0) == 0x3386; 92 + } 89 93 90 94 void pm3386_reset(void) 91 95 { 92 96 u8 mac[3][6]; 97 + int secondary; 98 + 99 + secondary = pm3386_secondary_present(); 93 100 94 101 /* Save programmed MAC addresses. */ 95 102 pm3386_get_mac(0, mac[0]); 96 103 pm3386_get_mac(1, mac[1]); 97 - pm3386_get_mac(2, mac[2]); 104 + if (secondary) 105 + pm3386_get_mac(2, mac[2]); 98 106 99 107 /* Assert analog and digital reset. */ 100 108 pm3386_reg_write(0, 0x002, 0x0060); 101 - pm3386_reg_write(1, 0x002, 0x0060); 109 + if (secondary) 110 + pm3386_reg_write(1, 0x002, 0x0060); 102 111 mdelay(1); 103 112 104 113 /* Deassert analog reset. */ 105 114 pm3386_reg_write(0, 0x002, 0x0062); 106 - pm3386_reg_write(1, 0x002, 0x0062); 115 + if (secondary) 116 + pm3386_reg_write(1, 0x002, 0x0062); 107 117 mdelay(10); 108 118 109 119 /* Deassert digital reset. */ 110 120 pm3386_reg_write(0, 0x002, 0x0063); 111 - pm3386_reg_write(1, 0x002, 0x0063); 121 + if (secondary) 122 + pm3386_reg_write(1, 0x002, 0x0063); 112 123 mdelay(10); 113 124 114 125 /* Restore programmed MAC addresses. */ 115 126 pm3386_set_mac(0, mac[0]); 116 127 pm3386_set_mac(1, mac[1]); 117 - pm3386_set_mac(2, mac[2]); 128 + if (secondary) 129 + pm3386_set_mac(2, mac[2]); 118 130 119 131 /* Disable carrier on all ports. */ 120 132 pm3386_set_carrier(0, 0); 121 133 pm3386_set_carrier(1, 0); 122 - pm3386_set_carrier(2, 0); 134 + if (secondary) 135 + pm3386_set_carrier(2, 0); 123 136 } 124 137 125 138 static u16 swaph(u16 x) 126 139 { 127 140 return ((x << 8) | (x >> 8)) & 0xffff; 141 + } 142 + 143 + int pm3386_port_count(void) 144 + { 145 + return 2 + pm3386_secondary_present(); 128 146 } 129 147 130 148 void pm3386_init_port(int port)
+1
drivers/net/ixp2000/pm3386.h
··· 13 13 #define __PM3386_H 14 14 15 15 void pm3386_reset(void); 16 + int pm3386_port_count(void); 16 17 void pm3386_init_port(int port); 17 18 void pm3386_get_mac(int port, u8 *mac); 18 19 void pm3386_set_mac(int port, u8 *mac);