| 1 |
/* |
|---|
| 2 |
* swconfig-ip175c.c: Swconfig configuration for IC+ IP175C switch |
|---|
| 3 |
* |
|---|
| 4 |
* Copyright (C) 2008 Patrick Horn <patrick.horn@gmail.com> |
|---|
| 5 |
* Copyright (C) 2008 Martin Mares <mj@ucw.cz> |
|---|
| 6 |
* Copyright (C) 2009 Felix Fietkau <nbd@openwrt.org> |
|---|
| 7 |
* |
|---|
| 8 |
* This program is free software; you can redistribute it and/or |
|---|
| 9 |
* modify it under the terms of the GNU General Public License |
|---|
| 10 |
* as published by the Free Software Foundation; either version 2 |
|---|
| 11 |
* of the License, or (at your option) any later version. |
|---|
| 12 |
* |
|---|
| 13 |
* This program is distributed in the hope that it will be useful, |
|---|
| 14 |
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
|---|
| 15 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|---|
| 16 |
* GNU General Public License for more details. |
|---|
| 17 |
*/ |
|---|
| 18 |
|
|---|
| 19 |
#include <linux/kernel.h> |
|---|
| 20 |
#include <linux/module.h> |
|---|
| 21 |
#include <linux/init.h> |
|---|
| 22 |
#include <linux/list.h> |
|---|
| 23 |
#include <linux/skbuff.h> |
|---|
| 24 |
#include <linux/mii.h> |
|---|
| 25 |
#include <linux/phy.h> |
|---|
| 26 |
#include <linux/delay.h> |
|---|
| 27 |
#include <linux/switch.h> |
|---|
| 28 |
|
|---|
| 29 |
#define MAX_VLANS 16 |
|---|
| 30 |
#define MAX_PORTS 9 |
|---|
| 31 |
|
|---|
| 32 |
typedef struct ip175c_reg { |
|---|
| 33 |
u16 p; // phy |
|---|
| 34 |
u16 m; // mii |
|---|
| 35 |
} reg; |
|---|
| 36 |
typedef char bitnum; |
|---|
| 37 |
|
|---|
| 38 |
#define NOTSUPPORTED {-1,-1} |
|---|
| 39 |
|
|---|
| 40 |
#define REG_SUPP(x) (((x).m != ((u16)-1)) && ((x).p != (u16)-1)) |
|---|
| 41 |
|
|---|
| 42 |
/*********** CONSTANTS ***********/ |
|---|
| 43 |
struct register_mappings { |
|---|
| 44 |
char *NAME; |
|---|
| 45 |
u16 MODEL_NO; // compare to bits 4-9 of MII register 0,3. |
|---|
| 46 |
bitnum NUM_PORTS; |
|---|
| 47 |
bitnum CPU_PORT; |
|---|
| 48 |
|
|---|
| 49 |
/* The default VLAN for each port. |
|---|
| 50 |
Default: 0x0001 for Ports 0,1,2,3 |
|---|
| 51 |
0x0002 for Ports 4,5 */ |
|---|
| 52 |
reg VLAN_DEFAULT_TAG_REG[MAX_PORTS]; |
|---|
| 53 |
|
|---|
| 54 |
/* These ports are tagged. |
|---|
| 55 |
Default: 0x00 */ |
|---|
| 56 |
reg ADD_TAG_REG; |
|---|
| 57 |
reg REMOVE_TAG_REG; |
|---|
| 58 |
bitnum ADD_TAG_BIT[MAX_PORTS]; |
|---|
| 59 |
/* These ports are untagged. |
|---|
| 60 |
Default: 0x00 (i.e. do not alter any VLAN tags...) |
|---|
| 61 |
Maybe set to 0 if user disables VLANs. */ |
|---|
| 62 |
bitnum REMOVE_TAG_BIT[MAX_PORTS]; |
|---|
| 63 |
|
|---|
| 64 |
/* Port M and Port N are on the same VLAN. |
|---|
| 65 |
Default: All ports on all VLANs. */ |
|---|
| 66 |
// Use register {29, 19+N/2} |
|---|
| 67 |
reg VLAN_LOOKUP_REG; |
|---|
| 68 |
// Port 5 uses register {30, 18} but same as odd bits. |
|---|
| 69 |
reg VLAN_LOOKUP_REG_5; // in a different register on IP175C. |
|---|
| 70 |
bitnum VLAN_LOOKUP_EVEN_BIT[MAX_PORTS]; |
|---|
| 71 |
bitnum VLAN_LOOKUP_ODD_BIT[MAX_PORTS]; |
|---|
| 72 |
|
|---|
| 73 |
/* This VLAN corresponds to which ports. |
|---|
| 74 |
Default: 0x2f,0x30,0x3f,0x3f... */ |
|---|
| 75 |
reg TAG_VLAN_MASK_REG; |
|---|
| 76 |
bitnum TAG_VLAN_MASK_EVEN_BIT[MAX_PORTS]; |
|---|
| 77 |
bitnum TAG_VLAN_MASK_ODD_BIT[MAX_PORTS]; |
|---|
| 78 |
|
|---|
| 79 |
int RESET_VAL; |
|---|
| 80 |
reg RESET_REG; |
|---|
| 81 |
|
|---|
| 82 |
reg MODE_REG; |
|---|
| 83 |
int MODE_VAL; |
|---|
| 84 |
|
|---|
| 85 |
/* General flags */ |
|---|
| 86 |
reg ROUTER_CONTROL_REG; |
|---|
| 87 |
reg VLAN_CONTROL_REG; |
|---|
| 88 |
bitnum TAG_VLAN_BIT; |
|---|
| 89 |
bitnum ROUTER_EN_BIT; |
|---|
| 90 |
bitnum NUMLAN_GROUPS_MAX; |
|---|
| 91 |
bitnum NUMLAN_GROUPS_BIT; |
|---|
| 92 |
|
|---|
| 93 |
reg MII_REGISTER_EN; |
|---|
| 94 |
bitnum MII_REGISTER_EN_BIT; |
|---|
| 95 |
|
|---|
| 96 |
// set to 1 for 178C, 0 for 175C. |
|---|
| 97 |
bitnum SIMPLE_VLAN_REGISTERS; // 175C has two vlans per register but 178C has only one. |
|---|
| 98 |
}; |
|---|
| 99 |
|
|---|
| 100 |
static const struct register_mappings IP178C = { |
|---|
| 101 |
.NAME = "IP178C", |
|---|
| 102 |
.MODEL_NO = 0x18, |
|---|
| 103 |
.VLAN_DEFAULT_TAG_REG = { |
|---|
| 104 |
{30,3},{30,4},{30,5},{30,6},{30,7},{30,8}, |
|---|
| 105 |
{30,9},{30,10},{30,11}, |
|---|
| 106 |
}, |
|---|
| 107 |
|
|---|
| 108 |
.ADD_TAG_REG = {30,12}, |
|---|
| 109 |
.ADD_TAG_BIT = {0,1,2,3,4,5,6,7,8}, |
|---|
| 110 |
.REMOVE_TAG_REG = {30,13}, |
|---|
| 111 |
.REMOVE_TAG_BIT = {4,5,6,7,8,9,10,11,12}, |
|---|
| 112 |
|
|---|
| 113 |
.SIMPLE_VLAN_REGISTERS = 1, |
|---|
| 114 |
|
|---|
| 115 |
.VLAN_LOOKUP_REG = {31,0},// +N |
|---|
| 116 |
.VLAN_LOOKUP_REG_5 = NOTSUPPORTED, // not used with SIMPLE_VLAN_REGISTERS |
|---|
| 117 |
.VLAN_LOOKUP_EVEN_BIT = {0,1,2,3,4,5,6,7,8}, |
|---|
| 118 |
.VLAN_LOOKUP_ODD_BIT = {0,1,2,3,4,5,6,7,8}, |
|---|
| 119 |
|
|---|
| 120 |
.TAG_VLAN_MASK_REG = {30,14}, // +N |
|---|
| 121 |
.TAG_VLAN_MASK_EVEN_BIT = {0,1,2,3,4,5,6,7,8}, |
|---|
| 122 |
.TAG_VLAN_MASK_ODD_BIT = {0,1,2,3,4,5,6,7,8}, |
|---|
| 123 |
|
|---|
| 124 |
.RESET_VAL = 0x55AA, |
|---|
| 125 |
.RESET_REG = {30,0}, |
|---|
| 126 |
.MODE_VAL = 0, |
|---|
| 127 |
.MODE_REG = NOTSUPPORTED, |
|---|
| 128 |
|
|---|
| 129 |
.ROUTER_CONTROL_REG = {30,30}, |
|---|
| 130 |
.ROUTER_EN_BIT = 11, |
|---|
| 131 |
.NUMLAN_GROUPS_MAX = 8, |
|---|
| 132 |
.NUMLAN_GROUPS_BIT = 8, // {0-2} |
|---|
| 133 |
|
|---|
| 134 |
.VLAN_CONTROL_REG = {30,13}, |
|---|
| 135 |
.TAG_VLAN_BIT = 3, |
|---|
| 136 |
|
|---|
| 137 |
.CPU_PORT = 8, |
|---|
| 138 |
.NUM_PORTS = 9, |
|---|
| 139 |
|
|---|
| 140 |
.MII_REGISTER_EN = NOTSUPPORTED, |
|---|
| 141 |
|
|---|
| 142 |
}; |
|---|
| 143 |
|
|---|
| 144 |
static const struct register_mappings IP175C = { |
|---|
| 145 |
.NAME = "IP175C", |
|---|
| 146 |
.MODEL_NO = 0x18, |
|---|
| 147 |
.VLAN_DEFAULT_TAG_REG = { |
|---|
| 148 |
{29,24},{29,25},{29,26},{29,27},{29,28},{29,30}, |
|---|
| 149 |
NOTSUPPORTED,NOTSUPPORTED,NOTSUPPORTED |
|---|
| 150 |
}, |
|---|
| 151 |
|
|---|
| 152 |
.ADD_TAG_REG = {29,23}, |
|---|
| 153 |
.REMOVE_TAG_REG = {29,23}, |
|---|
| 154 |
.ADD_TAG_BIT = {11,12,13,14,15,1,-1,-1,-1}, |
|---|
| 155 |
.REMOVE_TAG_BIT = {6,7,8,9,10,0,-1,-1,-1}, |
|---|
| 156 |
|
|---|
| 157 |
.SIMPLE_VLAN_REGISTERS = 0, |
|---|
| 158 |
|
|---|
| 159 |
.VLAN_LOOKUP_REG = {29,19},// +N/2 |
|---|
| 160 |
.VLAN_LOOKUP_REG_5 = {30,18}, |
|---|
| 161 |
.VLAN_LOOKUP_EVEN_BIT = {8,9,10,11,12,15,-1,-1,-1}, |
|---|
| 162 |
.VLAN_LOOKUP_ODD_BIT = {0,1,2,3,4,7,-1,-1,-1}, |
|---|
| 163 |
|
|---|
| 164 |
.TAG_VLAN_MASK_REG = {30,1}, // +N/2 |
|---|
| 165 |
.TAG_VLAN_MASK_EVEN_BIT = {0,1,2,3,4,5,-1,-1,-1}, |
|---|
| 166 |
.TAG_VLAN_MASK_ODD_BIT = {8,9,10,11,12,13,-1,-1,-1}, |
|---|
| 167 |
|
|---|
| 168 |
.RESET_VAL = 0x175C, |
|---|
| 169 |
.RESET_REG = {30,0}, |
|---|
| 170 |
.MODE_VAL = 0x175C, |
|---|
| 171 |
.MODE_REG = {29,31}, |
|---|
| 172 |
|
|---|
| 173 |
.ROUTER_CONTROL_REG = {30,9}, |
|---|
| 174 |
.ROUTER_EN_BIT = 3, |
|---|
| 175 |
.NUMLAN_GROUPS_MAX = 8, |
|---|
| 176 |
.NUMLAN_GROUPS_BIT = 0, // {0-2} |
|---|
| 177 |
|
|---|
| 178 |
.VLAN_CONTROL_REG = {30,9}, |
|---|
| 179 |
.TAG_VLAN_BIT = 7, |
|---|
| 180 |
|
|---|
| 181 |
.NUM_PORTS = 6, |
|---|
| 182 |
.CPU_PORT = 5, |
|---|
| 183 |
|
|---|
| 184 |
.MII_REGISTER_EN = NOTSUPPORTED, |
|---|
| 185 |
|
|---|
| 186 |
}; |
|---|
| 187 |
|
|---|
| 188 |
static const struct register_mappings IP175A = { |
|---|
| 189 |
.NAME = "IP175A", |
|---|
| 190 |
.MODEL_NO = 0x05, |
|---|
| 191 |
.VLAN_DEFAULT_TAG_REG = { |
|---|
| 192 |
{0,24},{0,25},{0,26},{0,27},{0,28},NOTSUPPORTED, |
|---|
| 193 |
NOTSUPPORTED,NOTSUPPORTED,NOTSUPPORTED |
|---|
| 194 |
}, |
|---|
| 195 |
|
|---|
| 196 |
.ADD_TAG_REG = {0,23}, |
|---|
| 197 |
.REMOVE_TAG_REG = {0,23}, |
|---|
| 198 |
.ADD_TAG_BIT = {11,12,13,14,15,1,-1,-1,-1}, |
|---|
| 199 |
.REMOVE_TAG_BIT = {6,7,8,9,10,0,-1,-1,-1}, |
|---|
| 200 |
|
|---|
| 201 |
.SIMPLE_VLAN_REGISTERS = 1, |
|---|
| 202 |
|
|---|
| 203 |
// Only programmable via. EEPROM |
|---|
| 204 |
.VLAN_LOOKUP_REG = NOTSUPPORTED,// +N/2 |
|---|
| 205 |
.VLAN_LOOKUP_REG_5 = NOTSUPPORTED, |
|---|
| 206 |
.VLAN_LOOKUP_EVEN_BIT = {8,9,10,11,12,15,-1,-1,-1}, |
|---|
| 207 |
.VLAN_LOOKUP_ODD_BIT = {0,1,2,3,4,7,-1,-1,-1}, |
|---|
| 208 |
|
|---|
| 209 |
.TAG_VLAN_MASK_REG = NOTSUPPORTED, // +N/2 |
|---|
| 210 |
.TAG_VLAN_MASK_EVEN_BIT = {0,1,2,3,4,5,-1,-1,-1}, |
|---|
| 211 |
.TAG_VLAN_MASK_ODD_BIT = {8,9,10,11,12,13,-1,-1,-1}, |
|---|
| 212 |
|
|---|
| 213 |
.RESET_VAL = -1, |
|---|
| 214 |
.RESET_REG = NOTSUPPORTED, |
|---|
| 215 |
.MODE_VAL = 0, |
|---|
| 216 |
.MODE_REG = NOTSUPPORTED, |
|---|
| 217 |
|
|---|
| 218 |
.ROUTER_CONTROL_REG = NOTSUPPORTED, |
|---|
| 219 |
.VLAN_CONTROL_REG = NOTSUPPORTED, |
|---|
| 220 |
.TAG_VLAN_BIT = -1, |
|---|
| 221 |
.ROUTER_EN_BIT = -1, |
|---|
| 222 |
.NUMLAN_GROUPS_MAX = -1, |
|---|
| 223 |
.NUMLAN_GROUPS_BIT = -1, // {0-2} |
|---|
| 224 |
|
|---|
| 225 |
.NUM_PORTS = 6, |
|---|
| 226 |
.CPU_PORT = 5, |
|---|
| 227 |
|
|---|
| 228 |
.MII_REGISTER_EN = {0, 12}, |
|---|
| 229 |
.MII_REGISTER_EN_BIT = 7, |
|---|
| 230 |
}; |
|---|
| 231 |
|
|---|
| 232 |
struct ip175c_state { |
|---|
| 233 |
struct switch_dev dev; |
|---|
| 234 |
struct mii_bus *mii_bus; |
|---|
| 235 |
bool registered; |
|---|
| 236 |
|
|---|
| 237 |
int router_mode; // ROUTER_EN |
|---|
| 238 |
int vlan_enabled; // TAG_VLAN_EN |
|---|
| 239 |
struct port_state { |
|---|
| 240 |
u16 pvid; |
|---|
| 241 |
unsigned int shareports; |
|---|
| 242 |
} ports[MAX_PORTS]; |
|---|
| 243 |
unsigned int add_tag; |
|---|
| 244 |
unsigned int remove_tag; |
|---|
| 245 |
int num_vlans; |
|---|
| 246 |
unsigned int vlan_ports[MAX_VLANS]; |
|---|
| 247 |
const struct register_mappings *regs; |
|---|
| 248 |
reg proc_mii; /*!< phy/reg for the low level register access via /proc */ |
|---|
| 249 |
|
|---|
| 250 |
char buf[80]; |
|---|
| 251 |
}; |
|---|
| 252 |
|
|---|
| 253 |
static int ip_phy_read(struct mii_bus *bus, int port, int reg) |
|---|
| 254 |
{ |
|---|
| 255 |
int val; |
|---|
| 256 |
|
|---|
| 257 |
spin_lock_bh(&bus->mdio_lock); |
|---|
| 258 |
val = bus->read(bus, port, reg); |
|---|
| 259 |
spin_unlock_bh(&bus->mdio_lock); |
|---|
| 260 |
|
|---|
| 261 |
return val; |
|---|
| 262 |
} |
|---|
| 263 |
|
|---|
| 264 |
|
|---|
| 265 |
static int ip_phy_write(struct mii_bus *bus, int port, int reg, u16 val) |
|---|
| 266 |
{ |
|---|
| 267 |
int err; |
|---|
| 268 |
|
|---|
| 269 |
spin_lock_bh(&bus->mdio_lock); |
|---|
| 270 |
err = bus->write(bus, port, reg, val); |
|---|
| 271 |
spin_unlock_bh(&bus->mdio_lock); |
|---|
| 272 |
|
|---|
| 273 |
return err; |
|---|
| 274 |
} |
|---|
| 275 |
|
|---|
| 276 |
|
|---|
| 277 |
static int getPhy (struct ip175c_state *state, reg mii) |
|---|
| 278 |
{ |
|---|
| 279 |
struct mii_bus *bus = state->mii_bus; |
|---|
| 280 |
int val; |
|---|
| 281 |
|
|---|
| 282 |
if (!REG_SUPP(mii)) |
|---|
| 283 |
return -EFAULT; |
|---|
| 284 |
|
|---|
| 285 |
val = ip_phy_read(bus, mii.p, mii.m); |
|---|
| 286 |
if (val < 0) |
|---|
| 287 |
printk(KERN_ERR "IP175C: Unable to get MII register %d,%d: error %d\n", mii.p,mii.m,-val); |
|---|
| 288 |
|
|---|
| 289 |
return val; |
|---|
| 290 |
} |
|---|
| 291 |
|
|---|
| 292 |
static int setPhy (struct ip175c_state *state, reg mii, u16 value) |
|---|
| 293 |
{ |
|---|
| 294 |
struct mii_bus *bus = state->mii_bus; |
|---|
| 295 |
int err; |
|---|
| 296 |
|
|---|
| 297 |
if (!REG_SUPP(mii)) |
|---|
| 298 |
return -EFAULT; |
|---|
| 299 |
|
|---|
| 300 |
err = ip_phy_write(bus, mii.p, mii.m, value); |
|---|
| 301 |
if (err < 0) { |
|---|
| 302 |
printk(KERN_ERR "IP175C: Unable to set MII register %d,%d to %d: error %d\n", mii.p,mii.m,value,-err); |
|---|
| 303 |
return err; |
|---|
| 304 |
} |
|---|
| 305 |
mdelay(2); |
|---|
| 306 |
getPhy(state, mii); |
|---|
| 307 |
return 0; |
|---|
| 308 |
} |
|---|
| 309 |
|
|---|
| 310 |
/** |
|---|
| 311 |
* These two macros are to simplify the mapping of logical bits to the bits in hardware. |
|---|
| 312 |
* NOTE: these macros will return if there is an error! |
|---|
| 313 |
*/ |
|---|
| 314 |
|
|---|
| 315 |
#define GET_PORT_BITS(state, bits, addr, bit_lookup) \ |
|---|
| 316 |
do { \ |
|---|
| 317 |
int i, val = getPhy((state), (addr)); \ |
|---|
| 318 |
if (val < 0) \ |
|---|
| 319 |
return val; \ |
|---|
| 320 |
(bits) = 0; \ |
|---|
| 321 |
for (i = 0; i < MAX_PORTS; i++) { \ |
|---|
| 322 |
if ((bit_lookup)[i] == -1) continue; \ |
|---|
| 323 |
if (val & (1<<(bit_lookup)[i])) \ |
|---|
| 324 |
(bits) |= (1<<i); \ |
|---|
| 325 |
} \ |
|---|
| 326 |
} while (0) |
|---|
| 327 |
|
|---|
| 328 |
#define SET_PORT_BITS(state, bits, addr, bit_lookup) \ |
|---|
| 329 |
do { \ |
|---|
| 330 |
int i, val = getPhy((state), (addr)); \ |
|---|
| 331 |
if (val < 0) \ |
|---|
| 332 |
return val; \ |
|---|
| 333 |
for (i = 0; i < MAX_PORTS; i++) { \ |
|---|
| 334 |
unsigned int newmask = ((bits)&(1<<i)); \ |
|---|
| 335 |
if ((bit_lookup)[i] == -1) continue; \ |
|---|
| 336 |
val &= ~(1<<(bit_lookup)[i]); \ |
|---|
| 337 |
val |= ((newmask>>i)<<(bit_lookup)[i]); \ |
|---|
| 338 |
} \ |
|---|
| 339 |
val = setPhy((state), (addr), val); \ |
|---|
| 340 |
if (val < 0) \ |
|---|
| 341 |
return val; \ |
|---|
| 342 |
} while (0) |
|---|
| 343 |
|
|---|
| 344 |
static int get_model(struct ip175c_state *state) |
|---|
| 345 |
{ |
|---|
| 346 |
reg oui_id_reg = {0, 2}; |
|---|
| 347 |
int oui_id; |
|---|
| 348 |
reg model_no_reg = {0, 3}; |
|---|
| 349 |
int model_no, model_no_orig; |
|---|
| 350 |
|
|---|
| 351 |
// 175 and 178 have the same oui ID. |
|---|
| 352 |
reg oui_id_reg_178c = {5, 2}; // returns error on IP175C. |
|---|
| 353 |
int is_178c = 0; |
|---|
| 354 |
|
|---|
| 355 |
oui_id = getPhy(state, oui_id_reg); |
|---|
| 356 |
if (oui_id != 0x0243) { |
|---|
| 357 |
// non |
|---|
| 358 |
return -ENODEV; // Not a IC+ chip. |
|---|
| 359 |
} |
|---|
| 360 |
oui_id = getPhy(state, oui_id_reg_178c); |
|---|
| 361 |
if (oui_id == 0x0243) { |
|---|
| 362 |
is_178c = 1; |
|---|
| 363 |
} |
|---|
| 364 |
|
|---|
| 365 |
model_no_orig = getPhy(state, model_no_reg); |
|---|
| 366 |
if (model_no_orig < 0) { |
|---|
| 367 |
return -ENODEV; |
|---|
| 368 |
} |
|---|
| 369 |
model_no = model_no_orig >> 4; // shift out revision number. |
|---|
| 370 |
model_no &= 0x3f; // only take the model number (low 6 bits). |
|---|
| 371 |
if (model_no == IP175A.MODEL_NO) { |
|---|
| 372 |
state->regs = &IP175A; |
|---|
| 373 |
} else if (model_no == IP175C.MODEL_NO) { |
|---|
| 374 |
if (is_178c) { |
|---|
| 375 |
state->regs = &IP178C; |
|---|
| 376 |
} else { |
|---|
| 377 |
state->regs = &IP175C; |
|---|
| 378 |
} |
|---|
| 379 |
} else { |
|---|
| 380 |
printk(KERN_WARNING "ip175c: Found an unknown IC+ switch with model number %02Xh.\n", model_no_orig); |
|---|
| 381 |
return -EPERM; |
|---|
| 382 |
} |
|---|
| 383 |
return 0; |
|---|
| 384 |
} |
|---|
| 385 |
|
|---|
| 386 |
/** Get only the vlan and router flags on the router **/ |
|---|
| 387 |
static int get_flags(struct ip175c_state *state) |
|---|
| 388 |
{ |
|---|
| 389 |
int val; |
|---|
| 390 |
|
|---|
| 391 |
state->router_mode = 0; |
|---|
| 392 |
state->vlan_enabled = -1; // hack |
|---|
| 393 |
state->num_vlans = 0; |
|---|
| 394 |
|
|---|
| 395 |
if (!REG_SUPP(state->regs->ROUTER_CONTROL_REG)) { |
|---|
| 396 |
return 0; // not an error if it doesn't support enable vlan. |
|---|
| 397 |
} |
|---|
| 398 |
|
|---|
| 399 |
val = getPhy(state, state->regs->ROUTER_CONTROL_REG); |
|---|
| 400 |
if (val < 0) { |
|---|
| 401 |
return val; |
|---|
| 402 |
} |
|---|
| 403 |
if (state->regs->ROUTER_EN_BIT >= 0) |
|---|
| 404 |
state->router_mode = ((val>>state->regs->ROUTER_EN_BIT) & 1); |
|---|
| 405 |
|
|---|
| 406 |
if (state->regs->NUMLAN_GROUPS_BIT >= 0) { |
|---|
| 407 |
state->num_vlans = (val >> state->regs->NUMLAN_GROUPS_BIT); |
|---|
| 408 |
state->num_vlans &= (state->regs->NUMLAN_GROUPS_MAX-1); |
|---|
| 409 |
state->num_vlans+=1; // does not include WAN. |
|---|
| 410 |
} |
|---|
| 411 |
|
|---|
| 412 |
|
|---|
| 413 |
val = getPhy(state, state->regs->VLAN_CONTROL_REG); |
|---|
| 414 |
if (val < 0) { |
|---|
| 415 |
return 0; |
|---|
| 416 |
} |
|---|
| 417 |
if (state->regs->TAG_VLAN_BIT >= 0) |
|---|
| 418 |
state->vlan_enabled = ((val>>state->regs->TAG_VLAN_BIT) & 1); |
|---|
| 419 |
|
|---|
| 420 |
return 0; |
|---|
| 421 |
} |
|---|
| 422 |
/** Get all state variables for VLAN mappings and port-based tagging. **/ |
|---|
| 423 |
static int get_state(struct ip175c_state *state) |
|---|
| 424 |
{ |
|---|
| 425 |
int i, j; |
|---|
| 426 |
int ret; |
|---|
| 427 |
ret = get_flags(state); |
|---|
| 428 |
if (ret < 0) { |
|---|
| 429 |
return ret; |
|---|
| 430 |
} |
|---|
| 431 |
GET_PORT_BITS(state, state->remove_tag, |
|---|
| 432 |
state->regs->REMOVE_TAG_REG, state->regs->REMOVE_TAG_BIT); |
|---|
| 433 |
GET_PORT_BITS(state, state->add_tag, |
|---|
| 434 |
state->regs->ADD_TAG_REG, state->regs->ADD_TAG_BIT); |
|---|
| 435 |
|
|---|
| 436 |
if (state->vlan_enabled == -1) { |
|---|
| 437 |
// not sure how to get this... |
|---|
| 438 |
state->vlan_enabled = (!state->remove_tag && !state->add_tag); |
|---|
| 439 |
} |
|---|
| 440 |
|
|---|
| 441 |
if (REG_SUPP(state->regs->VLAN_LOOKUP_REG)) { |
|---|
| 442 |
for (j=0; j<MAX_PORTS; j++) { |
|---|
| 443 |
state->ports[j].shareports = 0; // initialize them in case. |
|---|
| 444 |
} |
|---|
| 445 |
for (j=0; j<state->regs->NUM_PORTS; j++) { |
|---|
| 446 |
reg addr; |
|---|
| 447 |
const bitnum *bit_lookup = (j%2==0)? |
|---|
| 448 |
state->regs->VLAN_LOOKUP_EVEN_BIT: |
|---|
| 449 |
state->regs->VLAN_LOOKUP_ODD_BIT; |
|---|
| 450 |
addr = state->regs->VLAN_LOOKUP_REG; |
|---|
| 451 |
if (state->regs->SIMPLE_VLAN_REGISTERS) { |
|---|
| 452 |
addr.m += j; |
|---|
| 453 |
} else { |
|---|
| 454 |
switch (j) { |
|---|
| 455 |
case 0: |
|---|
| 456 |
case 1: |
|---|
| 457 |
break; |
|---|
| 458 |
case 2: |
|---|
| 459 |
case 3: |
|---|
| 460 |
addr.m+=1; |
|---|
| 461 |
break; |
|---|
| 462 |
case 4: |
|---|
| 463 |
addr.m+=2; |
|---|
| 464 |
break; |
|---|
| 465 |
case 5: |
|---|
| 466 |
addr = state->regs->VLAN_LOOKUP_REG_5; |
|---|
| 467 |
break; |
|---|
| 468 |
} |
|---|
| 469 |
} |
|---|
| 470 |
|
|---|
| 471 |
if (REG_SUPP(addr)) { |
|---|
| 472 |
GET_PORT_BITS(state, state->ports[j].shareports, addr, bit_lookup); |
|---|
| 473 |
} |
|---|
| 474 |
} |
|---|
| 475 |
} else { |
|---|
| 476 |
for (j=0; j<MAX_PORTS; j++) { |
|---|
| 477 |
state->ports[j].shareports = 0xff; |
|---|
| 478 |
} |
|---|
| 479 |
} |
|---|
| 480 |
|
|---|
| 481 |
for (i=0; i<MAX_PORTS; i++) { |
|---|
| 482 |
if (REG_SUPP(state->regs->VLAN_DEFAULT_TAG_REG[i])) { |
|---|
| 483 |
int val = getPhy(state, state->regs->VLAN_DEFAULT_TAG_REG[i]); |
|---|
| 484 |
if (val < 0) { |
|---|
| 485 |
return val; |
|---|
| 486 |
} |
|---|
| 487 |
state->ports[i].pvid = val; |
|---|
| 488 |
} else { |
|---|
| 489 |
state->ports[i].pvid = 0; |
|---|
| 490 |
} |
|---|
| 491 |
} |
|---|
| 492 |
|
|---|
| 493 |
if (REG_SUPP(state->regs->TAG_VLAN_MASK_REG)) { |
|---|
| 494 |
for (j=0; j<MAX_VLANS; j++) { |
|---|
| 495 |
reg addr = state->regs->TAG_VLAN_MASK_REG; |
|---|
| 496 |
const bitnum *bit_lookup = (j%2==0)? |
|---|
| 497 |
state->regs->TAG_VLAN_MASK_EVEN_BIT: |
|---|
| 498 |
state->regs->TAG_VLAN_MASK_ODD_BIT; |
|---|
| 499 |
if (state->regs->SIMPLE_VLAN_REGISTERS) { |
|---|
| 500 |
addr.m += j; |
|---|
| 501 |
} else { |
|---|
| 502 |
addr.m += j/2; |
|---|
| 503 |
} |
|---|
| 504 |
GET_PORT_BITS(state, state->vlan_ports[j], addr, bit_lookup); |
|---|
| 505 |
} |
|---|
| 506 |
} else { |
|---|
| 507 |
for (j=0; j<MAX_VLANS; j++) { |
|---|
| 508 |
state->vlan_ports[j] = 0; |
|---|
| 509 |
for (i=0; i<state->regs->NUM_PORTS; i++) { |
|---|
| 510 |
if ((state->ports[i].pvid == j) || |
|---|
| 511 |
(state->ports[i].pvid == 0)) { |
|---|
| 512 |
state->vlan_ports[j] |= (1<<i); |
|---|
| 513 |
} |
|---|
| 514 |
} |
|---|
| 515 |
} |
|---|
| 516 |
} |
|---|
| 517 |
|
|---|
| 518 |
return 0; |
|---|
| 519 |
} |
|---|
| 520 |
|
|---|
| 521 |
|
|---|
| 522 |
/** Only update vlan and router flags in the switch **/ |
|---|
| 523 |
static int update_flags(struct ip175c_state *state) |
|---|
| 524 |
{ |
|---|
| 525 |
int val; |
|---|
| 526 |
|
|---|
| 527 |
if (!REG_SUPP(state->regs->ROUTER_CONTROL_REG)) { |
|---|
| 528 |
return 0; |
|---|
| 529 |
} |
|---|
| 530 |
|
|---|
| 531 |
val = getPhy(state, state->regs->ROUTER_CONTROL_REG); |
|---|
| 532 |
if (val < 0) { |
|---|
| 533 |
return val; |
|---|
| 534 |
} |
|---|
| 535 |
if (state->regs->ROUTER_EN_BIT >= 0) { |
|---|
| 536 |
if (state->router_mode) { |
|---|
| 537 |
val |= (1<<state->regs->ROUTER_EN_BIT); |
|---|
| 538 |
} else { |
|---|
| 539 |
val &= (~(1<<state->regs->ROUTER_EN_BIT)); |
|---|
| 540 |
} |
|---|
| 541 |
} |
|---|
| 542 |
if (state->regs->TAG_VLAN_BIT >= 0) { |
|---|
| 543 |
if (state->vlan_enabled) { |
|---|
| 544 |
val |= (1<<state->regs->TAG_VLAN_BIT); |
|---|
| 545 |
} else { |
|---|
| 546 |
val &= (~(1<<state->regs->TAG_VLAN_BIT)); |
|---|
| 547 |
} |
|---|
| 548 |
} |
|---|
| 549 |
if (state->regs->NUMLAN_GROUPS_BIT >= 0) { |
|---|
| 550 |
val &= (~((state->regs->NUMLAN_GROUPS_MAX-1)<<state->regs->NUMLAN_GROUPS_BIT)); |
|---|
| 551 |
if (state->num_vlans > state->regs->NUMLAN_GROUPS_MAX) { |
|---|
| 552 |
val |= state->regs->NUMLAN_GROUPS_MAX << state->regs->NUMLAN_GROUPS_BIT; |
|---|
| 553 |
} else if (state->num_vlans >= 1) { |
|---|
| 554 |
val |= (state->num_vlans-1) << state->regs->NUMLAN_GROUPS_BIT; |
|---|
| 555 |
} |
|---|
| 556 |
} |
|---|
| 557 |
return setPhy(state, state->regs->ROUTER_CONTROL_REG, val); |
|---|
| 558 |
} |
|---|
| 559 |
|
|---|
| 560 |
/** Update all VLAN and port state. Usually you should call "correct_vlan_state" first. **/ |
|---|
| 561 |
static int update_state(struct ip175c_state *state) |
|---|
| 562 |
{ |
|---|
| 563 |
int j; |
|---|
| 564 |
int i; |
|---|
| 565 |
SET_PORT_BITS(state, state->add_tag, |
|---|
| 566 |
state->regs->ADD_TAG_REG, state->regs->ADD_TAG_BIT); |
|---|
| 567 |
SET_PORT_BITS(state, state->remove_tag, |
|---|
| 568 |
state->regs->REMOVE_TAG_REG, state->regs->REMOVE_TAG_BIT); |
|---|
| 569 |
|
|---|
| 570 |
if (REG_SUPP(state->regs->VLAN_LOOKUP_REG)) { |
|---|
| 571 |
for (j=0; j<state->regs->NUM_PORTS; j++) { |
|---|
| 572 |
reg addr; |
|---|
| 573 |
const bitnum *bit_lookup = (j%2==0)? |
|---|
| 574 |
state->regs->VLAN_LOOKUP_EVEN_BIT: |
|---|
| 575 |
state->regs->VLAN_LOOKUP_ODD_BIT; |
|---|
| 576 |
|
|---|
| 577 |
// duplicate code -- sorry |
|---|
| 578 |
addr = state->regs->VLAN_LOOKUP_REG; |
|---|
| 579 |
if (state->regs->SIMPLE_VLAN_REGISTERS) { |
|---|
| 580 |
addr.m += j; |
|---|
| 581 |
} else { |
|---|
| 582 |
switch (j) { |
|---|
| 583 |
case 0: |
|---|
| 584 |
case 1: |
|---|
| 585 |
break; |
|---|
| 586 |
case 2: |
|---|
| 587 |
case 3: |
|---|
| 588 |
addr.m+=1; |
|---|
| 589 |
break; |
|---|
| 590 |
case 4: |
|---|
| 591 |
addr.m+=2; |
|---|
| 592 |
break; |
|---|
| 593 |
case 5: |
|---|
| 594 |
addr = state->regs->VLAN_LOOKUP_REG_5; |
|---|
| 595 |
break; |
|---|
| 596 |
default: |
|---|
| 597 |
addr.m = -1; // shouldn't get here, but... |
|---|
| 598 |
break; |
|---|
| 599 |
} |
|---|
| 600 |
} |
|---|
| 601 |
//printf("shareports for %d is %02X\n",j,state->ports[j].shareports); |
|---|
| 602 |
if (REG_SUPP(addr)) { |
|---|
| 603 |
SET_PORT_BITS(state, state->ports[j].shareports, addr, bit_lookup); |
|---|
| 604 |
} |
|---|
| 605 |
} |
|---|
| 606 |
} |
|---|
| 607 |
if (REG_SUPP(state->regs->TAG_VLAN_MASK_REG)) { |
|---|
| 608 |
for (j=0; j<MAX_VLANS; j++) { |
|---|
| 609 |
reg addr = state->regs->TAG_VLAN_MASK_REG; |
|---|
| 610 |
const bitnum *bit_lookup = (j%2==0)? |
|---|
| 611 |
state->regs->TAG_VLAN_MASK_EVEN_BIT: |
|---|
| 612 |
state->regs->TAG_VLAN_MASK_ODD_BIT; |
|---|
| 613 |
unsigned int vlan_mask; |
|---|
| 614 |
if (state->regs->SIMPLE_VLAN_REGISTERS) { |
|---|
| 615 |
addr.m += j; |
|---|
| 616 |
} else { |
|---|
| 617 |
addr.m += j/2; |
|---|
| 618 |
} |
|---|
| 619 |
vlan_mask = state->vlan_ports[j]; |
|---|
| 620 |
SET_PORT_BITS(state, vlan_mask, addr, bit_lookup); |
|---|
| 621 |
} |
|---|
| 622 |
} |
|---|
| 623 |
|
|---|
| 624 |
for (i=0; i<MAX_PORTS; i++) { |
|---|
| 625 |
if (REG_SUPP(state->regs->VLAN_DEFAULT_TAG_REG[i])) { |
|---|
| 626 |
int err = setPhy(state, state->regs->VLAN_DEFAULT_TAG_REG[i], |
|---|
| 627 |
state->ports[i].pvid); |
|---|
| 628 |
if (err < 0) { |
|---|
| 629 |
return err; |
|---|
| 630 |
} |
|---|
| 631 |
} |
|---|
| 632 |
} |
|---|
| 633 |
|
|---|
| 634 |
return update_flags(state); |
|---|
| 635 |
|
|---|
| 636 |
// software reset: 30.0 = 0x175C |
|---|
| 637 |
// wait 2ms |
|---|
| 638 |
// reset ports 0,1,2,3,4 |
|---|
| 639 |
} |
|---|
| 640 |
|
|---|
| 641 |
/* |
|---|
| 642 |
Uses only the VLAN port mask and the add tag mask to generate the other fields: |
|---|
| 643 |
which ports are part of the same VLAN, removing vlan tags, and VLAN tag ids. |
|---|
| 644 |
*/ |
|---|
| 645 |
static void correct_vlan_state(struct ip175c_state *state) |
|---|
| 646 |
{ |
|---|
| 647 |
int i, j; |
|---|
| 648 |
state->num_vlans = 0; |
|---|
| 649 |
for (i=0; i<MAX_VLANS; i++) { |
|---|
| 650 |
if (state->vlan_ports[i] != 0) { |
|---|
| 651 |
state->num_vlans = i+1; //hack -- we need to store the "set" vlans somewhere... |
|---|
| 652 |
} |
|---|
| 653 |
} |
|---|
| 654 |
|
|---|
| 655 |
|
|---|
| 656 |
|
|---|
| 657 |
for (i=0; i<state->regs->NUM_PORTS; i++) { |
|---|
| 658 |
unsigned int portmask = (1<<i); |
|---|
| 659 |
if (!state->vlan_enabled) { |
|---|
| 660 |
// share with everybody! |
|---|
| 661 |
state->ports[i].shareports = (1<<state->regs->NUM_PORTS)-1; |
|---|
| 662 |
continue; |
|---|
| 663 |
} |
|---|
| 664 |
state->ports[i].shareports = portmask; |
|---|
| 665 |
for (j=0; j<MAX_VLANS; j++) { |
|---|
| 666 |
if (state->vlan_ports[j] & portmask) |
|---|
| 667 |
state->ports[i].shareports |= state->vlan_ports[j]; |
|---|
| 668 |
} |
|---|
| 669 |
} |
|---|
| 670 |
state->remove_tag = ((~state->add_tag) & ((1<<state->regs->NUM_PORTS)-1)); |
|---|
| 671 |
} |
|---|
| 672 |
|
|---|
| 673 |
static int ip175c_get_enable_vlan(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val) |
|---|
| 674 |
{ |
|---|
| 675 |
struct ip175c_state *state = dev->priv; |
|---|
| 676 |
int err; |
|---|
| 677 |
|
|---|
| 678 |
err = get_state(state); // may be set in get_state. |
|---|
| 679 |
if (err < 0) |
|---|
| 680 |
return err; |
|---|
| 681 |
val->value.i = state->vlan_enabled; |
|---|
| 682 |
return 0; |
|---|
| 683 |
} |
|---|
| 684 |
|
|---|
| 685 |
static int ip175c_set_enable_vlan(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val) |
|---|
| 686 |
{ |
|---|
| 687 |
struct ip175c_state *state = dev->priv; |
|---|
| 688 |
int err; |
|---|
| 689 |
int enable; |
|---|
| 690 |
int i; |
|---|
| 691 |
|
|---|
| 692 |
err = get_state(state); |
|---|
| 693 |
if (err < 0) |
|---|
| 694 |
return err; |
|---|
| 695 |
enable = val->value.i; |
|---|
| 696 |
|
|---|
| 697 |
if (state->vlan_enabled == enable) { |
|---|
| 698 |
// do not change any state. |
|---|
| 699 |
return 0; |
|---|
| 700 |
} |
|---|
| 701 |
state->vlan_enabled = enable; |
|---|
| 702 |
|
|---|
| 703 |
// Otherwise, if we are switching state, set fields to a known default. |
|---|
| 704 |
state->remove_tag = 0x0000; |
|---|
| 705 |
state->add_tag = 0x0000; |
|---|
| 706 |
for (i = 0; i < MAX_PORTS; i++) |
|---|
| 707 |
state->ports[i].shareports = 0xffff; |
|---|
| 708 |
|
|---|
| 709 |
for (i = 0; i < MAX_VLANS; i++) |
|---|
| 710 |
state->vlan_ports[i] = 0x0; |
|---|
| 711 |
|
|---|
| 712 |
if (state->vlan_enabled) { |
|---|
| 713 |
// updates other fields only based off vlan_ports and add_tag fields. |
|---|
| 714 |
// Note that by default, no ports are in any vlans. |
|---|
| 715 |
correct_vlan_state(state); |
|---|
| 716 |
} |
|---|
| 717 |
// ensure sane defaults? |
|---|
| 718 |
return update_state(state); |
|---|
| 719 |
} |
|---|
| 720 |
|
|---|
| 721 |
static int ip175c_get_ports(struct switch_dev *dev, struct switch_val *val) |
|---|
| 722 |
{ |
|---|
| 723 |
struct ip175c_state *state = dev->priv; |
|---|
| 724 |
int err; |
|---|
| 725 |
int b; |
|---|
| 726 |
int ind; |
|---|
| 727 |
unsigned int ports; |
|---|
| 728 |
|
|---|
| 729 |
if (val->port_vlan >= dev->vlans || val->port_vlan < 0) |
|---|
| 730 |
return -EINVAL; |
|---|
| 731 |
|
|---|
| 732 |
err = get_state(state); |
|---|
| 733 |
if (err<0) |
|---|
| 734 |
return err; |
|---|
| 735 |
|
|---|
| 736 |
ports = state->vlan_ports[val->port_vlan]; |
|---|
| 737 |
b = 0; |
|---|
| 738 |
ind = 0; |
|---|
| 739 |
while (b < MAX_PORTS) { |
|---|
| 740 |
if (ports&1) { |
|---|
| 741 |
int istagged = ((state->add_tag >> b) & 1); |
|---|
| 742 |
val->value.ports[ind].id = b; |
|---|
| 743 |
val->value.ports[ind].flags = (istagged << SWITCH_PORT_FLAG_TAGGED); |
|---|
| 744 |
ind++; |
|---|
| 745 |
} |
|---|
| 746 |
b++; |
|---|
| 747 |
ports >>= 1; |
|---|
| 748 |
} |
|---|
| 749 |
val->len = ind; |
|---|
| 750 |
|
|---|
| 751 |
return 0; |
|---|
| 752 |
} |
|---|
| 753 |
|
|---|
| 754 |
static int ip175c_set_ports(struct switch_dev *dev, struct switch_val *val) |
|---|
| 755 |
{ |
|---|
| 756 |
struct ip175c_state *state = dev->priv; |
|---|
| 757 |
int i; |
|---|
| 758 |
int err; |
|---|
| 759 |
|
|---|
| 760 |
if (val->port_vlan >= dev->vlans || val->port_vlan < 0) |
|---|
| 761 |
return -EINVAL; |
|---|
| 762 |
|
|---|
| 763 |
err = get_state(state); |
|---|
| 764 |
if (err < 0) |
|---|
| 765 |
return err; |
|---|
| 766 |
|
|---|
| 767 |
state->vlan_ports[val->port_vlan] = 0; |
|---|
| 768 |
for (i = 0; i < val->len; i++) { |
|---|
| 769 |
int bitmask = (1<<val->value.ports[i].id); |
|---|
| 770 |
state->vlan_ports[val->port_vlan] |= bitmask; |
|---|
| 771 |
if (val->value.ports[i].flags & (1<<SWITCH_PORT_FLAG_TAGGED)) { |
|---|
| 772 |
state->add_tag |= bitmask; |
|---|
| 773 |
} else { |
|---|
| 774 |
state->add_tag &= (~bitmask); |
|---|
| 775 |
} |
|---|
| 776 |
} |
|---|
| 777 |
|
|---|
| 778 |
correct_vlan_state(state); |
|---|
| 779 |
err = update_state(state); |
|---|
| 780 |
|
|---|
| 781 |
return err; |
|---|
| 782 |
} |
|---|
| 783 |
|
|---|
| 784 |
static int ip175c_apply(struct switch_dev *dev) |
|---|
| 785 |
{ |
|---|
| 786 |
struct ip175c_state *state = dev->priv; |
|---|
| 787 |
int err; |
|---|
| 788 |
|
|---|
| 789 |
err = get_flags(state); |
|---|
| 790 |
if (err < 0) |
|---|
| 791 |
return err; |
|---|
| 792 |
|
|---|
| 793 |
if (REG_SUPP(state->regs->MII_REGISTER_EN)){ |
|---|
| 794 |
int val = getPhy(state, state->regs->MII_REGISTER_EN); |
|---|
| 795 |
if (val < 0) { |
|---|
| 796 |
return val; |
|---|
| 797 |
} |
|---|
| 798 |
val |= (1<<state->regs->MII_REGISTER_EN_BIT); |
|---|
| 799 |
return setPhy(state, state->regs->MII_REGISTER_EN, val); |
|---|
| 800 |
} |
|---|
| 801 |
return 0; |
|---|
| 802 |
} |
|---|
| 803 |
|
|---|
| 804 |
static int ip175c_reset(struct switch_dev *dev) |
|---|
| 805 |
{ |
|---|
| 806 |
struct ip175c_state *state = dev->priv; |
|---|
| 807 |
int i, err; |
|---|
| 808 |
|
|---|
| 809 |
err = get_flags(state); |
|---|
| 810 |
if (err < 0) |
|---|
| 811 |
return err; |
|---|
| 812 |
|
|---|
| 813 |
if (REG_SUPP(state->regs->RESET_REG)) { |
|---|
| 814 |
err = setPhy(state, state->regs->RESET_REG, state->regs->RESET_VAL); |
|---|
| 815 |
if (err < 0) |
|---|
| 816 |
return err; |
|---|
| 817 |
err = getPhy(state, state->regs->RESET_REG); |
|---|
| 818 |
|
|---|
| 819 |
/* data sheet specifies reset period is 2 msec |
|---|
| 820 |
(don't see any mention of the 2ms delay in the IP178C spec, only |
|---|
| 821 |
in IP175C, but it can't hurt.) */ |
|---|
| 822 |
mdelay(2); |
|---|
| 823 |
} |
|---|
| 824 |
|
|---|
| 825 |
if (REG_SUPP(state->regs->MODE_REG)) { |
|---|
| 826 |
err = setPhy(state, state->regs->MODE_REG, state->regs->RESET_VAL); |
|---|
| 827 |
if (err < 0) |
|---|
| 828 |
return err; |
|---|
| 829 |
err = getPhy(state, state->regs->MODE_REG); |
|---|
| 830 |
} |
|---|
| 831 |
|
|---|
| 832 |
/* reset switch ports */ |
|---|
| 833 |
for (i = 0; i < 5; i++) { |
|---|
| 834 |
err = state->mii_bus->write(state->mii_bus, i, |
|---|
| 835 |
MII_BMCR, BMCR_RESET); |
|---|
| 836 |
if (err < 0) |
|---|
| 837 |
return err; |
|---|
| 838 |
} |
|---|
| 839 |
|
|---|
| 840 |
return 0; |
|---|
| 841 |
} |
|---|
| 842 |
|
|---|
| 843 |
/*! get the current register number */ |
|---|
| 844 |
static int ip175c_get_tagged(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val) |
|---|
| 845 |
{ |
|---|
| 846 |
struct ip175c_state *state = dev->priv; |
|---|
| 847 |
int err; |
|---|
| 848 |
|
|---|
| 849 |
err = get_state(state); |
|---|
| 850 |
if (err < 0) |
|---|
| 851 |
return err; |
|---|
| 852 |
|
|---|
| 853 |
if (state->add_tag & (1<<val->port_vlan)) { |
|---|
| 854 |
if (state->remove_tag & (1<<val->port_vlan)) |
|---|
| 855 |
val->value.i = 3; // shouldn't ever happen. |
|---|
| 856 |
else |
|---|
| 857 |
val->value.i = 1; |
|---|
| 858 |
} else { |
|---|
| 859 |
if (state->remove_tag & (1<<val->port_vlan)) |
|---|
| 860 |
val->value.i = 0; |
|---|
| 861 |
else |
|---|
| 862 |
val->value.i = 2; |
|---|
| 863 |
} |
|---|
| 864 |
return 0; |
|---|
| 865 |
} |
|---|
| 866 |
|
|---|
| 867 |
/*! set a new register address for low level access to registers */ |
|---|
| 868 |
static int ip175c_set_tagged(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val) |
|---|
| 869 |
{ |
|---|
| 870 |
struct ip175c_state *state = dev->priv; |
|---|
| 871 |
int err; |
|---|
| 872 |
|
|---|
| 873 |
err = get_state(state); |
|---|
| 874 |
if (err < 0) |
|---|
| 875 |
return err; |
|---|
| 876 |
|
|---|
| 877 |
state->add_tag &= ~(1<<val->port_vlan); |
|---|
| 878 |
state->remove_tag &= ~(1<<val->port_vlan); |
|---|
| 879 |
|
|---|
| 880 |
if (val->value.i == 0) |
|---|
| 881 |
state->remove_tag |= (1<<val->port_vlan); |
|---|
| 882 |
if (val->value.i == 1) |
|---|
| 883 |
state->add_tag |= (1<<val->port_vlan); |
|---|
| 884 |
|
|---|
| 885 |
SET_PORT_BITS(state, state->add_tag, |
|---|
| 886 |
state->regs->ADD_TAG_REG, state->regs->ADD_TAG_BIT); |
|---|
| 887 |
SET_PORT_BITS(state, state->remove_tag, |
|---|
| 888 |
state->regs->REMOVE_TAG_REG, state->regs->REMOVE_TAG_BIT); |
|---|
| 889 |
|
|---|
| 890 |
return err; |
|---|
| 891 |
} |
|---|
| 892 |
|
|---|
| 893 |
|
|---|
| 894 |
/* low level /proc procedures */ |
|---|
| 895 |
|
|---|
| 896 |
/*! get the current phy address */ |
|---|
| 897 |
static int ip175c_get_phy(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val) |
|---|
| 898 |
{ |
|---|
| 899 |
struct ip175c_state *state = dev->priv; |
|---|
| 900 |
|
|---|
| 901 |
val->value.i = state->proc_mii.p; |
|---|
| 902 |
return 0; |
|---|
| 903 |
} |
|---|
| 904 |
|
|---|
| 905 |
/*! set a new phy address for low level access to registers */ |
|---|
| 906 |
static int ip175c_set_phy(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val) |
|---|
| 907 |
{ |
|---|
| 908 |
struct ip175c_state *state = dev->priv; |
|---|
| 909 |
int new_reg = val->value.i; |
|---|
| 910 |
|
|---|
| 911 |
if (new_reg < 0 || new_reg > 31) |
|---|
| 912 |
state->proc_mii.p = (u16)-1; |
|---|
| 913 |
else |
|---|
| 914 |
state->proc_mii.p = (u16)new_reg; |
|---|
| 915 |
return 0; |
|---|
| 916 |
} |
|---|
| 917 |
|
|---|
| 918 |
/*! get the current register number */ |
|---|
| 919 |
static int ip175c_get_reg(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val) |
|---|
| 920 |
{ |
|---|
| 921 |
struct ip175c_state *state = dev->priv; |
|---|
| 922 |
|
|---|
| 923 |
val->value.i = state->proc_mii.m; |
|---|
| 924 |
return 0; |
|---|
| 925 |
} |
|---|
| 926 |
|
|---|
| 927 |
/*! set a new register address for low level access to registers */ |
|---|
| 928 |
static int ip175c_set_reg(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val) |
|---|
| 929 |
{ |
|---|
| 930 |
struct ip175c_state *state = dev->priv; |
|---|
| 931 |
int new_reg = val->value.i; |
|---|
| 932 |
|
|---|
| 933 |
if (new_reg < 0 || new_reg > 31) |
|---|
| 934 |
state->proc_mii.m = (u16)-1; |
|---|
| 935 |
else |
|---|
| 936 |
state->proc_mii.m = (u16)new_reg; |
|---|
| 937 |
return 0; |
|---|
| 938 |
} |
|---|
| 939 |
|
|---|
| 940 |
/*! get the register content of state->proc_mii */ |
|---|
| 941 |
static int ip175c_get_val(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val) |
|---|
| 942 |
{ |
|---|
| 943 |
struct ip175c_state *state = dev->priv; |
|---|
| 944 |
int retval = -EINVAL; |
|---|
| 945 |
if (REG_SUPP(state->proc_mii)) |
|---|
| 946 |
retval = getPhy(state, state->proc_mii); |
|---|
| 947 |
|
|---|
| 948 |
if (retval < 0) { |
|---|
| 949 |
return retval; |
|---|
| 950 |
} else { |
|---|
| 951 |
val->value.i = retval; |
|---|
| 952 |
return 0; |
|---|
| 953 |
} |
|---|
| 954 |
} |
|---|
| 955 |
|
|---|
| 956 |
/*! write a value to the register defined by phy/reg above */ |
|---|
| 957 |
static int ip175c_set_val(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val) |
|---|
| 958 |
{ |
|---|
| 959 |
struct ip175c_state *state = dev->priv; |
|---|
| 960 |
int myval, err = 0; |
|---|
| 961 |
|
|---|
| 962 |
myval = val->value.i; |
|---|
| 963 |
if (myval <= 0xffff && myval >= 0 && REG_SUPP(state->proc_mii)) { |
|---|
| 964 |
err = setPhy(state, state->proc_mii, (u16)myval); |
|---|
| 965 |
} |
|---|
| 966 |
return err; |
|---|
| 967 |
} |
|---|
| 968 |
|
|---|
| 969 |
static int ip175c_read_name(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val) |
|---|
| 970 |
{ |
|---|
| 971 |
struct ip175c_state *state = dev->priv; |
|---|
| 972 |
val->value.s = state->regs->NAME; // just a const pointer, won't be freed by swconfig. |
|---|
| 973 |
return 0; |
|---|
| 974 |
} |
|---|
| 975 |
|
|---|
| 976 |
|
|---|
| 977 |
static int ip175c_set_port_speed(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val) |
|---|
| 978 |
{ |
|---|
| 979 |
struct ip175c_state *state = dev->priv; |
|---|
| 980 |
struct mii_bus *bus = state->mii_bus; |
|---|
| 981 |
int nr = val->port_vlan; |
|---|
| 982 |
int ctrl; |
|---|
| 983 |
int autoneg; |
|---|
| 984 |
int speed; |
|---|
| 985 |
if (val->value.i == 100) { |
|---|
| 986 |
speed = 1; |
|---|
| 987 |
autoneg = 0; |
|---|
| 988 |
} else if (val->value.i == 10) { |
|---|
| 989 |
speed = 0; |
|---|
| 990 |
autoneg = 0; |
|---|
| 991 |
} else { |
|---|
| 992 |
autoneg = 1; |
|---|
| 993 |
speed = 1; |
|---|
| 994 |
} |
|---|
| 995 |
|
|---|
| 996 |
/* can't set speed for cpu port */ |
|---|
| 997 |
if (nr == state->regs->CPU_PORT) |
|---|
| 998 |
return -EINVAL; |
|---|
| 999 |
|
|---|
| 1000 |
if (nr >= dev->ports || nr < 0) |
|---|
| 1001 |
return -EINVAL; |
|---|
| 1002 |
|
|---|
| 1003 |
ctrl = ip_phy_read(bus, nr, 0); |
|---|
| 1004 |
if (ctrl < 0) |
|---|
| 1005 |
return -EIO; |
|---|
| 1006 |
|
|---|
| 1007 |
ctrl &= (~(1<<12)); |
|---|
| 1008 |
ctrl &= (~(1<<13)); |
|---|
| 1009 |
ctrl |= (autoneg<<12); |
|---|
| 1010 |
ctrl |= (speed<<13); |
|---|
| 1011 |
|
|---|
| 1012 |
return ip_phy_write(bus, nr, 0, ctrl); |
|---|
| 1013 |
} |
|---|
| 1014 |
|
|---|
| 1015 |
static int ip175c_get_port_speed(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val) |
|---|
| 1016 |
{ |
|---|
| 1017 |
struct ip175c_state *state = dev->priv; |
|---|
| 1018 |
struct mii_bus *bus = state->mii_bus; |
|---|
| 1019 |
int nr = val->port_vlan; |
|---|
| 1020 |
int speed, status; |
|---|
| 1021 |
|
|---|
| 1022 |
if (nr == state->regs->CPU_PORT) { |
|---|
| 1023 |
val->value.i = 100; |
|---|
| 1024 |
return 0; |
|---|
| 1025 |
} |
|---|
| 1026 |
|
|---|
| 1027 |
if (nr >= dev->ports || nr < 0) |
|---|
| 1028 |
return -EINVAL; |
|---|
| 1029 |
|
|---|
| 1030 |
status = ip_phy_read(bus, nr, 1); |
|---|
| 1031 |
speed = ip_phy_read(bus, nr, 18); |
|---|
| 1032 |
if (status < 0 || speed < 0) |
|---|
| 1033 |
return -EIO; |
|---|
| 1034 |
|
|---|
| 1035 |
if (status & 4) |
|---|
| 1036 |
val->value.i = ((speed & (1<<11)) ? 100 : 10); |
|---|
| 1037 |
else |
|---|
| 1038 |
val->value.i = 0; |
|---|
| 1039 |
|
|---|
| 1040 |
return 0; |
|---|
| 1041 |
} |
|---|
| 1042 |
|
|---|
| 1043 |
|
|---|
| 1044 |
static int ip175c_get_port_status(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val) |
|---|
| 1045 |
{ |
|---|
| 1046 |
struct ip175c_state *state = dev->priv; |
|---|
| 1047 |
struct mii_bus *bus = state->mii_bus; |
|---|
| 1048 |
int ctrl, speed, status; |
|---|
| 1049 |
int nr = val->port_vlan; |
|---|
| 1050 |
int len; |
|---|
| 1051 |
char *buf = state->buf; // fixed-length at 80. |
|---|
| 1052 |
|
|---|
| 1053 |
if (nr == state->regs->CPU_PORT) { |
|---|
| 1054 |
sprintf(buf, "up, 100 Mbps, cpu port"); |
|---|
| 1055 |
val->value.s = buf; |
|---|
| 1056 |
return 0; |
|---|
| 1057 |
} |
|---|
| 1058 |
|
|---|
| 1059 |
if (nr >= dev->ports || nr < 0) |
|---|
| 1060 |
return -EINVAL; |
|---|
| 1061 |
|
|---|
| 1062 |
ctrl = ip_phy_read(bus, nr, 0); |
|---|
| 1063 |
status = ip_phy_read(bus, nr, 1); |
|---|
| 1064 |
speed = ip_phy_read(bus, nr, 18); |
|---|
| 1065 |
if (ctrl < 0 || status < 0 || speed < 0) |
|---|
| 1066 |
return -EIO; |
|---|
| 1067 |
|
|---|
| 1068 |
if (status & 4) |
|---|
| 1069 |
len = sprintf(buf, "up, %d Mbps, %s duplex", |
|---|
| 1070 |
((speed & (1<<11)) ? 100 : 10), |
|---|
| 1071 |
((speed & (1<<10)) ? "full" : "half")); |
|---|
| 1072 |
else |
|---|
| 1073 |
len = sprintf(buf, "down"); |
|---|
| 1074 |
|
|---|
| 1075 |
if (ctrl & (1<<12)) { |
|---|
| 1076 |
len += sprintf(buf+len, ", auto-negotiate"); |
|---|
| 1077 |
if (!(status & (1<<5))) |
|---|
| 1078 |
len += sprintf(buf+len, " (in progress)"); |
|---|
| 1079 |
} else { |
|---|
| 1080 |
len += sprintf(buf+len, ", fixed speed (%d)", |
|---|
| 1081 |
((ctrl & (1<<13)) ? 100 : 10)); |
|---|
| 1082 |
} |
|---|
| 1083 |
|
|---|
| 1084 |
buf[len] = '\0'; |
|---|
| 1085 |
val->value.s = buf; |
|---|
| 1086 |
return 0; |
|---|
| 1087 |
} |
|---|
| 1088 |
|
|---|
| 1089 |
static int ip175c_get_pvid(struct switch_dev *dev, int port, int *val) |
|---|
| 1090 |
{ |
|---|
| 1091 |
struct ip175c_state *state = dev->priv; |
|---|
| 1092 |
|
|---|
| 1093 |
*val = state->ports[port].pvid; |
|---|
| 1094 |
return 0; |
|---|
| 1095 |
} |
|---|
| 1096 |
|
|---|
| 1097 |
static int ip175c_set_pvid(struct switch_dev *dev, int port, int val) |
|---|
| 1098 |
{ |
|---|
| 1099 |
struct ip175c_state *state = dev->priv; |
|---|
| 1100 |
|
|---|
| 1101 |
state->ports[port].pvid = val; |
|---|
| 1102 |
|
|---|
| 1103 |
if (!REG_SUPP(state->regs->VLAN_DEFAULT_TAG_REG[port])) |
|---|
| 1104 |
return 0; |
|---|
| 1105 |
|
|---|
| 1106 |
return setPhy(state, state->regs->VLAN_DEFAULT_TAG_REG[port], val); |
|---|
| 1107 |
} |
|---|
| 1108 |
|
|---|
| 1109 |
|
|---|
| 1110 |
enum Ports { |
|---|
| 1111 |
IP175C_PORT_STATUS, |
|---|
| 1112 |
IP175C_PORT_LINK, |
|---|
| 1113 |
IP175C_PORT_TAGGED, |
|---|
| 1114 |
IP175C_PORT_PVID, |
|---|
| 1115 |
}; |
|---|
| 1116 |
|
|---|
| 1117 |
enum Globals { |
|---|
| 1118 |
IP175C_ENABLE_VLAN, |
|---|
| 1119 |
IP175C_GET_NAME, |
|---|
| 1120 |
IP175C_REGISTER_PHY, |
|---|
| 1121 |
IP175C_REGISTER_MII, |
|---|
| 1122 |
IP175C_REGISTER_VALUE, |
|---|
| 1123 |
IP175C_REGISTER_ERRNO, |
|---|
| 1124 |
}; |
|---|
| 1125 |
|
|---|
| 1126 |
static const struct switch_attr ip175c_global[] = { |
|---|
| 1127 |
[IP175C_ENABLE_VLAN] = { |
|---|
| 1128 |
.id = IP175C_ENABLE_VLAN, |
|---|
| 1129 |
.type = SWITCH_TYPE_INT, |
|---|
| 1130 |
.name = "enable_vlan", |
|---|
| 1131 |
.description = "Flag to enable or disable VLANs and tagging", |
|---|
| 1132 |
.get = ip175c_get_enable_vlan, |
|---|
| 1133 |
.set = ip175c_set_enable_vlan, |
|---|
| 1134 |
}, |
|---|
| 1135 |
[IP175C_GET_NAME] = { |
|---|
| 1136 |
.id = IP175C_GET_NAME, |
|---|
| 1137 |
.type = SWITCH_TYPE_STRING, |
|---|
| 1138 |
.description = "Returns the type of IC+ chip.", |
|---|
| 1139 |
.name = "name", |
|---|
| 1140 |
.get = ip175c_read_name, |
|---|
| 1141 |
.set = NULL, |
|---|
| 1142 |
}, |
|---|
| 1143 |
/* jal: added for low level debugging etc. */ |
|---|
| 1144 |
[IP175C_REGISTER_PHY] = { |
|---|
| 1145 |
.id = IP175C_REGISTER_PHY, |
|---|
| 1146 |
.type = SWITCH_TYPE_INT, |
|---|
| 1147 |
.description = "Direct register access: set phy (0-4, or 29,30,31)", |
|---|
| 1148 |
.name = "phy", |
|---|
| 1149 |
.get = ip175c_get_phy, |
|---|
| 1150 |
.set = ip175c_set_phy, |
|---|
| 1151 |
}, |
|---|
| 1152 |
[IP175C_REGISTER_MII] = { |
|---|
| 1153 |
.id = IP175C_REGISTER_MII, |
|---|
| 1154 |
.type = SWITCH_TYPE_INT, |
|---|
| 1155 |
.description = "Direct register access: set mii number (0-31)", |
|---|
| 1156 |
.name = "reg", |
|---|
| 1157 |
.get = ip175c_get_reg, |
|---|
| 1158 |
.set = ip175c_set_reg, |
|---|
| 1159 |
}, |
|---|
| 1160 |
[IP175C_REGISTER_VALUE] = { |
|---|
| 1161 |
.id = IP175C_REGISTER_VALUE, |
|---|
| 1162 |
.type = SWITCH_TYPE_INT, |
|---|
| 1163 |
.description = "Direct register access: read/write to register (0-65535)", |
|---|
| 1164 |
.name = "val", |
|---|
| 1165 |
.get = ip175c_get_val, |
|---|
| 1166 |
.set = ip175c_set_val, |
|---|
| 1167 |
}, |
|---|
| 1168 |
}; |
|---|
| 1169 |
|
|---|
| 1170 |
static const struct switch_attr ip175c_vlan[] = { |
|---|
| 1171 |
}; |
|---|
| 1172 |
|
|---|
| 1173 |
static const struct switch_attr ip175c_port[] = { |
|---|
| 1174 |
[IP175C_PORT_STATUS] = { |
|---|
| 1175 |
.id = IP175C_PORT_STATUS, |
|---|
| 1176 |
.type = SWITCH_TYPE_STRING, |
|---|
| 1177 |
.description = "Returns Detailed port status", |
|---|
| 1178 |
.name = "status", |
|---|
| 1179 |
.get = ip175c_get_port_status, |
|---|
| 1180 |
.set = NULL, |
|---|
| 1181 |
}, |
|---|
| 1182 |
[IP175C_PORT_LINK] = { |
|---|
| 1183 |
.id = IP175C_PORT_LINK, |
|---|
| 1184 |
.type = SWITCH_TYPE_INT, |
|---|
| 1185 |
.description = "Link speed. Can write 0 for auto-negotiate, or 10 or 100", |
|---|
| 1186 |
.name = "link", |
|---|
| 1187 |
.get = ip175c_get_port_speed, |
|---|
| 1188 |
.set = ip175c_set_port_speed, |
|---|
| 1189 |
}, |
|---|
| 1190 |
[IP175C_PORT_TAGGED] = { |
|---|
| 1191 |
.id = IP175C_PORT_LINK, |
|---|
| 1192 |
.type = SWITCH_TYPE_INT, |
|---|
| 1193 |
.description = "0 = untag, 1 = add tags, 2 = do not alter (This value is reset if vlans are altered)", |
|---|
| 1194 |
.name = "tagged", |
|---|
| 1195 |
.get = ip175c_get_tagged, |
|---|
| 1196 |
.set = ip175c_set_tagged, |
|---|
| 1197 |
}, |
|---|
| 1198 |
}; |
|---|
| 1199 |
|
|---|
| 1200 |
static int ip175c_probe(struct phy_device *pdev) |
|---|
| 1201 |
{ |
|---|
| 1202 |
struct ip175c_state *state; |
|---|
| 1203 |
struct switch_dev *dev; |
|---|
| 1204 |
int err; |
|---|
| 1205 |
|
|---|
| 1206 |
/* we only attach to PHY 0, but use all available PHYs */ |
|---|
| 1207 |
if (pdev->addr != 0) |
|---|
| 1208 |
return -ENODEV; |
|---|
| 1209 |
|
|---|
| 1210 |
state = kzalloc(sizeof(*state), GFP_KERNEL); |
|---|
| 1211 |
if (!state) |
|---|
| 1212 |
return -ENOMEM; |
|---|
| 1213 |
|
|---|
| 1214 |
dev = &state->dev; |
|---|
| 1215 |
dev->attr_global.attr = ip175c_global; |
|---|
| 1216 |
dev->attr_global.n_attr = ARRAY_SIZE(ip175c_global); |
|---|
| 1217 |
dev->attr_port.attr = ip175c_port; |
|---|
| 1218 |
dev->attr_port.n_attr = ARRAY_SIZE(ip175c_port); |
|---|
| 1219 |
dev->attr_vlan.attr = ip175c_vlan; |
|---|
| 1220 |
dev->attr_vlan.n_attr = ARRAY_SIZE(ip175c_vlan); |
|---|
| 1221 |
|
|---|
| 1222 |
dev->get_port_pvid = ip175c_get_pvid; |
|---|
| 1223 |
dev->set_port_pvid = ip175c_set_pvid; |
|---|
| 1224 |
dev->get_vlan_ports = ip175c_get_ports; |
|---|
| 1225 |
dev->set_vlan_ports = ip175c_set_ports; |
|---|
| 1226 |
dev->apply_config = ip175c_apply; |
|---|
| 1227 |
dev->reset_switch = ip175c_reset; |
|---|
| 1228 |
|
|---|
| 1229 |
dev->priv = state; |
|---|
| 1230 |
pdev->priv = state; |
|---|
| 1231 |
state->mii_bus = pdev->bus; |
|---|
| 1232 |
|
|---|
| 1233 |
err = get_model(state); |
|---|
| 1234 |
if (err < 0) |
|---|
| 1235 |
goto error; |
|---|
| 1236 |
|
|---|
| 1237 |
dev->vlans = MAX_VLANS; |
|---|
| 1238 |
dev->cpu_port = state->regs->CPU_PORT; |
|---|
| 1239 |
dev->ports = state->regs->NUM_PORTS; |
|---|
| 1240 |
dev->name = state->regs->NAME; |
|---|
| 1241 |
|
|---|
| 1242 |
return 0; |
|---|
| 1243 |
|
|---|
| 1244 |
error: |
|---|
| 1245 |
kfree(state); |
|---|
| 1246 |
return err; |
|---|
| 1247 |
} |
|---|
| 1248 |
|
|---|
| 1249 |
static int ip175c_config_init(struct phy_device *pdev) |
|---|
| 1250 |
{ |
|---|
| 1251 |
struct ip175c_state *state = pdev->priv; |
|---|
| 1252 |
struct net_device *dev = pdev->attached_dev; |
|---|
| 1253 |
int err; |
|---|
| 1254 |
|
|---|
| 1255 |
pdev->irq = PHY_IGNORE_INTERRUPT; |
|---|
| 1256 |
err = register_switch(&state->dev, dev); |
|---|
| 1257 |
if (err < 0) |
|---|
| 1258 |
return err; |
|---|
| 1259 |
|
|---|
| 1260 |
ip175c_reset(&state->dev); |
|---|
| 1261 |
|
|---|
| 1262 |
state->registered = true; |
|---|
| 1263 |
netif_carrier_on(pdev->attached_dev); |
|---|
| 1264 |
|
|---|
| 1265 |
return 0; |
|---|
| 1266 |
} |
|---|
| 1267 |
|
|---|
| 1268 |
static void ip175c_remove(struct phy_device *pdev) |
|---|
| 1269 |
{ |
|---|
| 1270 |
struct ip175c_state *state = pdev->priv; |
|---|
| 1271 |
|
|---|
| 1272 |
if (state->registered) |
|---|
| 1273 |
unregister_switch(&state->dev); |
|---|
| 1274 |
kfree(state); |
|---|
| 1275 |
} |
|---|
| 1276 |
|
|---|
| 1277 |
static int ip175c_config_aneg(struct phy_device *pdev) |
|---|
| 1278 |
{ |
|---|
| 1279 |
return 0; |
|---|
| 1280 |
} |
|---|
| 1281 |
|
|---|
| 1282 |
static int ip175c_read_status(struct phy_device *pdev) |
|---|
| 1283 |
{ |
|---|
| 1284 |
pdev->speed = SPEED_100; |
|---|
| 1285 |
pdev->duplex = DUPLEX_FULL; |
|---|
| 1286 |
pdev->pause = pdev->asym_pause = 0; |
|---|
| 1287 |
return 0; |
|---|
| 1288 |
} |
|---|
| 1289 |
|
|---|
| 1290 |
static struct phy_driver ip175c_driver = { |
|---|
| 1291 |
.name = "IC+ IP175C", |
|---|
| 1292 |
.phy_id = 0x02430d80, |
|---|
| 1293 |
.phy_id_mask = 0x0ffffff0, |
|---|
| 1294 |
.features = PHY_BASIC_FEATURES, |
|---|
| 1295 |
.probe = ip175c_probe, |
|---|
| 1296 |
.remove = ip175c_remove, |
|---|
| 1297 |
.config_init = ip175c_config_init, |
|---|
| 1298 |
.config_aneg = ip175c_config_aneg, |
|---|
| 1299 |
.read_status = ip175c_read_status, |
|---|
| 1300 |
.driver = { .owner = THIS_MODULE }, |
|---|
| 1301 |
}; |
|---|
| 1302 |
|
|---|
| 1303 |
|
|---|
| 1304 |
int __init ip175c_init(void) |
|---|
| 1305 |
{ |
|---|
| 1306 |
return phy_driver_register(&ip175c_driver); |
|---|
| 1307 |
} |
|---|
| 1308 |
|
|---|
| 1309 |
void __exit ip175c_exit(void) |
|---|
| 1310 |
{ |
|---|
| 1311 |
phy_driver_unregister(&ip175c_driver); |
|---|
| 1312 |
} |
|---|
| 1313 |
|
|---|
| 1314 |
MODULE_AUTHOR("Patrick Horn <patrick.horn@gmail.com>"); |
|---|
| 1315 |
MODULE_AUTHOR("Felix Fietkau <nbd@openwrt.org>"); |
|---|
| 1316 |
MODULE_LICENSE("GPL"); |
|---|
| 1317 |
|
|---|
| 1318 |
module_init(ip175c_init); |
|---|
| 1319 |
module_exit(ip175c_exit); |
|---|
| 1320 |
|
|---|