X-Git-Url: http://git.rohieb.name/openwrt.git/blobdiff_plain/6c0e4e5864ce8edbbb1b64061997ca93894ee8ca..27c4924de89ab58db82de5bf5b34781ff2665a45:/target/linux/generic-2.6/files/drivers/net/phy/ip175c.c diff --git a/target/linux/generic-2.6/files/drivers/net/phy/ip175c.c b/target/linux/generic-2.6/files/drivers/net/phy/ip175c.c index 00144e886..706c973c1 100644 --- a/target/linux/generic-2.6/files/drivers/net/phy/ip175c.c +++ b/target/linux/generic-2.6/files/drivers/net/phy/ip175c.c @@ -40,6 +40,8 @@ typedef char bitnum; #define REG_SUPP(x) (((x).m != ((u16)-1)) && ((x).p != (u16)-1)) +struct ip175c_state; + /*********** CONSTANTS ***********/ struct register_mappings { char *NAME; @@ -96,8 +98,21 @@ struct register_mappings { // set to 1 for 178C, 0 for 175C. bitnum SIMPLE_VLAN_REGISTERS; // 175C has two vlans per register but 178C has only one. + + // Pointers to functions which manipulate hardware state + int (*get_flags)(struct ip175c_state *state); + int (*get_state)(struct ip175c_state *state); + int (*update_state)(struct ip175c_state *state); + int (*set_vlan_mode)(struct ip175c_state *state); + int (*reset)(struct ip175c_state *state); }; +static int ip175c_get_flags(struct ip175c_state *state); +static int ip175c_get_state(struct ip175c_state *state); +static int ip175c_update_state(struct ip175c_state *state); +static int ip175c_set_vlan_mode(struct ip175c_state *state); +static int ip175c_do_reset(struct ip175c_state *state); + static const struct register_mappings IP178C = { .NAME = "IP178C", .MODEL_NO = 0x18, @@ -140,6 +155,11 @@ static const struct register_mappings IP178C = { .MII_REGISTER_EN = NOTSUPPORTED, + .get_flags = ip175c_get_flags, + .get_state = ip175c_get_state, + .update_state = ip175c_update_state, + .set_vlan_mode = ip175c_set_vlan_mode, + .reset = ip175c_do_reset, }; static const struct register_mappings IP175C = { @@ -184,6 +204,11 @@ static const struct register_mappings IP175C = { .MII_REGISTER_EN = NOTSUPPORTED, + .get_flags = ip175c_get_flags, + .get_state = ip175c_get_state, + .update_state = ip175c_update_state, + .set_vlan_mode = ip175c_set_vlan_mode, + .reset = ip175c_do_reset, }; static const struct register_mappings IP175A = { @@ -228,6 +253,12 @@ static const struct register_mappings IP175A = { .MII_REGISTER_EN = {0, 18}, .MII_REGISTER_EN_BIT = 7, + + .get_flags = ip175c_get_flags, + .get_state = ip175c_get_state, + .update_state = ip175c_update_state, + .set_vlan_mode = ip175c_set_vlan_mode, + .reset = ip175c_do_reset, }; @@ -245,7 +276,10 @@ struct ip175c_state { unsigned int add_tag; unsigned int remove_tag; int num_vlans; - unsigned int vlan_ports[MAX_VLANS]; + struct vlan_state { + unsigned int ports; + unsigned int tag; // VLAN tag (IP175D only) + } vlans[MAX_VLANS]; const struct register_mappings *regs; reg proc_mii; // phy/reg for the low level register access via swconfig @@ -385,7 +419,7 @@ static int get_model(struct ip175c_state *state) } /** Get only the vlan and router flags on the router **/ -static int get_flags(struct ip175c_state *state) +static int ip175c_get_flags(struct ip175c_state *state) { int val; @@ -421,14 +455,16 @@ static int get_flags(struct ip175c_state *state) } /** Get all state variables for VLAN mappings and port-based tagging **/ -static int get_state(struct ip175c_state *state) +static int ip175c_get_state(struct ip175c_state *state) { int i, j; int ret; - ret = get_flags(state); + + ret = ip175c_get_flags(state); if (ret < 0) { return ret; } + GET_PORT_BITS(state, state->remove_tag, state->regs->REMOVE_TAG_REG, state->regs->REMOVE_TAG_BIT); GET_PORT_BITS(state, state->add_tag, @@ -440,39 +476,39 @@ static int get_state(struct ip175c_state *state) } if (REG_SUPP(state->regs->VLAN_LOOKUP_REG)) { - for (j=0; jports[j].shareports = 0; // initialize them in case. - } - for (j=0; jregs->NUM_PORTS; j++) { - reg addr; - const bitnum *bit_lookup = (j%2==0)? - state->regs->VLAN_LOOKUP_EVEN_BIT: - state->regs->VLAN_LOOKUP_ODD_BIT; - addr = state->regs->VLAN_LOOKUP_REG; - if (state->regs->SIMPLE_VLAN_REGISTERS) { - addr.m += j; - } else { - switch (j) { - case 0: - case 1: - break; - case 2: - case 3: - addr.m+=1; - break; - case 4: - addr.m+=2; - break; - case 5: - addr = state->regs->VLAN_LOOKUP_REG_5; - break; - } + for (j=0; jports[j].shareports = 0; // initialize them in case. } + for (j=0; jregs->NUM_PORTS; j++) { + reg addr; + const bitnum *bit_lookup = (j%2==0)? + state->regs->VLAN_LOOKUP_EVEN_BIT: + state->regs->VLAN_LOOKUP_ODD_BIT; + addr = state->regs->VLAN_LOOKUP_REG; + if (state->regs->SIMPLE_VLAN_REGISTERS) { + addr.m += j; + } else { + switch (j) { + case 0: + case 1: + break; + case 2: + case 3: + addr.m+=1; + break; + case 4: + addr.m+=2; + break; + case 5: + addr = state->regs->VLAN_LOOKUP_REG_5; + break; + } + } - if (REG_SUPP(addr)) { - GET_PORT_BITS(state, state->ports[j].shareports, addr, bit_lookup); + if (REG_SUPP(addr)) { + GET_PORT_BITS(state, state->ports[j].shareports, addr, bit_lookup); + } } - } } else { for (j=0; jports[j].shareports = 0xff; @@ -502,15 +538,15 @@ static int get_state(struct ip175c_state *state) } else { addr.m += j/2; } - GET_PORT_BITS(state, state->vlan_ports[j], addr, bit_lookup); + GET_PORT_BITS(state, state->vlans[j].ports, addr, bit_lookup); } } else { for (j=0; jvlan_ports[j] = 0; + state->vlans[j].ports = 0; for (i=0; iregs->NUM_PORTS; i++) { if ((state->ports[i].pvid == j) || (state->ports[i].pvid == 0)) { - state->vlan_ports[j] |= (1<vlans[j].ports |= (1<regs->ROUTER_CONTROL_REG, val); } -/** Update all VLAN and port state. Usually you should call "correct_vlan_state" first. **/ -static int update_state(struct ip175c_state *state) +/** Set all VLAN and port state. Usually you should call "correct_vlan_state" first. **/ +static int ip175c_set_state(struct ip175c_state *state) { int j; int i; @@ -568,57 +604,57 @@ static int update_state(struct ip175c_state *state) state->regs->REMOVE_TAG_REG, state->regs->REMOVE_TAG_BIT); if (REG_SUPP(state->regs->VLAN_LOOKUP_REG)) { - for (j=0; jregs->NUM_PORTS; j++) { - reg addr; - const bitnum *bit_lookup = (j%2==0)? - state->regs->VLAN_LOOKUP_EVEN_BIT: - state->regs->VLAN_LOOKUP_ODD_BIT; - - // duplicate code -- sorry - addr = state->regs->VLAN_LOOKUP_REG; - if (state->regs->SIMPLE_VLAN_REGISTERS) { - addr.m += j; - } else { - switch (j) { - case 0: - case 1: - break; - case 2: - case 3: - addr.m+=1; - break; - case 4: - addr.m+=2; - break; - case 5: - addr = state->regs->VLAN_LOOKUP_REG_5; - break; - default: - addr.m = -1; // shouldn't get here, but... - break; + for (j=0; jregs->NUM_PORTS; j++) { + reg addr; + const bitnum *bit_lookup = (j%2==0)? + state->regs->VLAN_LOOKUP_EVEN_BIT: + state->regs->VLAN_LOOKUP_ODD_BIT; + + // duplicate code -- sorry + addr = state->regs->VLAN_LOOKUP_REG; + if (state->regs->SIMPLE_VLAN_REGISTERS) { + addr.m += j; + } else { + switch (j) { + case 0: + case 1: + break; + case 2: + case 3: + addr.m+=1; + break; + case 4: + addr.m+=2; + break; + case 5: + addr = state->regs->VLAN_LOOKUP_REG_5; + break; + default: + addr.m = -1; // shouldn't get here, but... + break; + } + } + //printf("shareports for %d is %02X\n",j,state->ports[j].shareports); + if (REG_SUPP(addr)) { + SET_PORT_BITS(state, state->ports[j].shareports, addr, bit_lookup); } - } - //printf("shareports for %d is %02X\n",j,state->ports[j].shareports); - if (REG_SUPP(addr)) { - SET_PORT_BITS(state, state->ports[j].shareports, addr, bit_lookup); } } - } if (REG_SUPP(state->regs->TAG_VLAN_MASK_REG)) { - for (j=0; jregs->TAG_VLAN_MASK_REG; - const bitnum *bit_lookup = (j%2==0)? - state->regs->TAG_VLAN_MASK_EVEN_BIT: - state->regs->TAG_VLAN_MASK_ODD_BIT; - unsigned int vlan_mask; - if (state->regs->SIMPLE_VLAN_REGISTERS) { - addr.m += j; - } else { - addr.m += j/2; + for (j=0; jregs->TAG_VLAN_MASK_REG; + const bitnum *bit_lookup = (j%2==0)? + state->regs->TAG_VLAN_MASK_EVEN_BIT: + state->regs->TAG_VLAN_MASK_ODD_BIT; + unsigned int vlan_mask; + if (state->regs->SIMPLE_VLAN_REGISTERS) { + addr.m += j; + } else { + addr.m += j/2; + } + vlan_mask = state->vlans[j].ports; + SET_PORT_BITS(state, vlan_mask, addr, bit_lookup); } - vlan_mask = state->vlan_ports[j]; - SET_PORT_BITS(state, vlan_mask, addr, bit_lookup); - } } for (i=0; inum_vlans = 0; for (i=0; ivlan_ports[i] != 0) { + if (state->vlans[i].ports != 0) { state->num_vlans = i+1; // Hack -- we need to store the "set" vlans somewhere... } } @@ -657,11 +693,37 @@ static void correct_vlan_state(struct ip175c_state *state) } state->ports[i].shareports = portmask; for (j=0; jvlan_ports[j] & portmask) - state->ports[i].shareports |= state->vlan_ports[j]; + if (state->vlans[j].ports & portmask) + state->ports[i].shareports |= state->vlans[j].ports; } } - state->remove_tag = ((~state->add_tag) & ((1<regs->NUM_PORTS)-1)); +} + +static int ip175c_update_state(struct ip175c_state *state) +{ + ip175c_correct_vlan_state(state); + return ip175c_set_state(state); +} + +static int ip175c_set_vlan_mode(struct ip175c_state *state) +{ + return ip175c_update_state(state); +} + +static int ip175c_do_reset(struct ip175c_state *state) +{ + int err; + + if (REG_SUPP(state->regs->MODE_REG)) { + err = setPhy(state, state->regs->MODE_REG, state->regs->MODE_VAL); + if (err < 0) + return err; + err = getPhy(state, state->regs->MODE_REG); + if (err < 0) + return err; + } + + return 0; } static int ip175c_get_enable_vlan(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val) @@ -669,21 +731,34 @@ static int ip175c_get_enable_vlan(struct switch_dev *dev, const struct switch_at struct ip175c_state *state = dev->priv; int err; - err = get_state(state); // May be set in get_state. + err = state->regs->get_state(state); // May be set in get_state. if (err < 0) return err; val->value.i = state->vlan_enabled; return 0; } +static void ip175c_reset_vlan_config(struct ip175c_state *state) +{ + int i; + + state->remove_tag = (state->vlan_enabled ? ((1<regs->NUM_PORTS)-1) : 0x0000); + state->add_tag = 0x0000; + for (i = 0; i < MAX_VLANS; i++) { + state->vlans[i].ports = 0x0000; + state->vlans[i].tag = (i ? i : 16); + } + for (i = 0; i < MAX_PORTS; i++) + state->ports[i].pvid = 0; +} + static int ip175c_set_enable_vlan(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val) { struct ip175c_state *state = dev->priv; int err; int enable; - int i; - err = get_state(state); + err = state->regs->get_state(state); if (err < 0) return err; enable = val->value.i; @@ -695,21 +770,9 @@ static int ip175c_set_enable_vlan(struct switch_dev *dev, const struct switch_at state->vlan_enabled = enable; // Otherwise, if we are switching state, set fields to a known default. - state->remove_tag = 0x0000; - state->add_tag = 0x0000; - for (i = 0; i < MAX_PORTS; i++) - state->ports[i].shareports = 0xffff; + ip175c_reset_vlan_config(state); - for (i = 0; i < MAX_VLANS; i++) - state->vlan_ports[i] = 0x0; - - if (state->vlan_enabled) { - // Updates other fields only based off vlan_ports and add_tag fields. - // Note that by default, no ports are in any vlans. - correct_vlan_state(state); - } - // Ensure sane defaults? - return update_state(state); + return state->regs->set_vlan_mode(state); } static int ip175c_get_ports(struct switch_dev *dev, struct switch_val *val) @@ -723,11 +786,11 @@ static int ip175c_get_ports(struct switch_dev *dev, struct switch_val *val) if (val->port_vlan >= dev->vlans || val->port_vlan < 0) return -EINVAL; - err = get_state(state); + err = state->regs->get_state(state); if (err<0) return err; - ports = state->vlan_ports[val->port_vlan]; + ports = state->vlans[val->port_vlan].ports; b = 0; ind = 0; while (b < MAX_PORTS) { @@ -754,25 +817,24 @@ static int ip175c_set_ports(struct switch_dev *dev, struct switch_val *val) if (val->port_vlan >= dev->vlans || val->port_vlan < 0) return -EINVAL; - err = get_state(state); + err = state->regs->get_state(state); if (err < 0) return err; - state->vlan_ports[val->port_vlan] = 0; + state->vlans[val->port_vlan].ports = 0; for (i = 0; i < val->len; i++) { - int bitmask = (1<value.ports[i].id); - state->vlan_ports[val->port_vlan] |= bitmask; + unsigned int bitmask = (1<value.ports[i].id); + state->vlans[val->port_vlan].ports |= bitmask; if (val->value.ports[i].flags & (1<add_tag |= bitmask; + state->remove_tag &= (~bitmask); } else { state->add_tag &= (~bitmask); + state->remove_tag |= bitmask; } } - correct_vlan_state(state); - err = update_state(state); - - return err; + return state->regs->update_state(state); } static int ip175c_apply(struct switch_dev *dev) @@ -780,7 +842,7 @@ static int ip175c_apply(struct switch_dev *dev) struct ip175c_state *state = dev->priv; int err; - err = get_flags(state); + err = state->regs->get_flags(state); if (err < 0) return err; @@ -800,7 +862,7 @@ static int ip175c_reset(struct switch_dev *dev) struct ip175c_state *state = dev->priv; int i, err; - err = get_flags(state); + err = state->regs->get_flags(state); if (err < 0) return err; @@ -818,13 +880,6 @@ static int ip175c_reset(struct switch_dev *dev) mdelay(2); } - if (REG_SUPP(state->regs->MODE_REG)) { - err = setPhy(state, state->regs->MODE_REG, state->regs->RESET_VAL); - if (err < 0) - return err; - err = getPhy(state, state->regs->MODE_REG); - } - /* reset switch ports */ for (i = 0; i < state->regs->NUM_PORTS-1; i++) { err = ip_phy_write(state, i, MII_BMCR, BMCR_RESET); @@ -832,7 +887,9 @@ static int ip175c_reset(struct switch_dev *dev) return err; } - return 0; + ip175c_reset_vlan_config(state); + + return state->regs->reset(state); } static int ip175c_get_tagged(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val) @@ -840,7 +897,7 @@ static int ip175c_get_tagged(struct switch_dev *dev, const struct switch_attr *a struct ip175c_state *state = dev->priv; int err; - err = get_state(state); + err = state->regs->get_state(state); if (err < 0) return err; @@ -863,7 +920,7 @@ static int ip175c_set_tagged(struct switch_dev *dev, const struct switch_attr *a struct ip175c_state *state = dev->priv; int err; - err = get_state(state); + err = state->regs->get_state(state); if (err < 0) return err; @@ -875,12 +932,7 @@ static int ip175c_set_tagged(struct switch_dev *dev, const struct switch_attr *a if (val->value.i == 1) state->add_tag |= (1<port_vlan); - SET_PORT_BITS(state, state->add_tag, - state->regs->ADD_TAG_REG, state->regs->ADD_TAG_BIT); - SET_PORT_BITS(state, state->remove_tag, - state->regs->REMOVE_TAG_REG, state->regs->REMOVE_TAG_BIT); - - return err; + return state->regs->update_state(state); } /** Get the current phy address */ @@ -947,7 +999,7 @@ static int ip175c_get_val(struct switch_dev *dev, const struct switch_attr *attr static int ip175c_set_val(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val) { struct ip175c_state *state = dev->priv; - int myval, err = 0; + int myval, err = -EINVAL; myval = val->value.i; if (myval <= 0xffff && myval >= 0 && REG_SUPP(state->proc_mii)) { @@ -963,6 +1015,34 @@ static int ip175c_read_name(struct switch_dev *dev, const struct switch_attr *at return 0; } +static int ip175c_get_tag(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val) +{ + struct ip175c_state *state = dev->priv; + int vlan = val->port_vlan; + + if (vlan < 0 || vlan >= MAX_VLANS) + return -EINVAL; + + val->value.i = state->vlans[vlan].tag; + return 0; +} + +static int ip175c_set_tag(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val) +{ + struct ip175c_state *state = dev->priv; + int vlan = val->port_vlan; + int tag = val->value.i; + + if (vlan < 0 || vlan >= MAX_VLANS) + return -EINVAL; + + if (tag < 0 || tag > 4095) + return -EINVAL; + + state->vlans[vlan].tag = tag; + return state->regs->update_state(state); +} + static int ip175c_set_port_speed(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val) { struct ip175c_state *state = dev->priv; @@ -1082,13 +1162,18 @@ static int ip175c_get_pvid(struct switch_dev *dev, int port, int *val) static int ip175c_set_pvid(struct switch_dev *dev, int port, int val) { struct ip175c_state *state = dev->priv; + int err; - state->ports[port].pvid = val; + if (val < 0 || val >= MAX_VLANS) + return -EINVAL; - if (!REG_SUPP(state->regs->VLAN_DEFAULT_TAG_REG[port])) - return 0; + err = state->regs->get_state(state); + if (err < 0) + return err; + + state->ports[port].pvid = val; - return setPhy(state, state->regs->VLAN_DEFAULT_TAG_REG[port], val); + return state->regs->update_state(state); } @@ -1108,6 +1193,10 @@ enum Globals { IP175C_REGISTER_ERRNO, }; +enum Vlans { + IP175C_VLAN_TAG, +}; + static const struct switch_attr ip175c_global[] = { [IP175C_ENABLE_VLAN] = { .id = IP175C_ENABLE_VLAN, @@ -1153,6 +1242,14 @@ static const struct switch_attr ip175c_global[] = { }; static const struct switch_attr ip175c_vlan[] = { + [IP175C_VLAN_TAG] = { + .id = IP175C_VLAN_TAG, + .type = SWITCH_TYPE_INT, + .description = "VLAN tag (0-4095) [IP175D only]", + .name = "tag", + .get = ip175c_get_tag, + .set = ip175c_set_tag, + } }; static const struct switch_attr ip175c_port[] = {