X-Git-Url: http://git.rohieb.name/openwrt.git/blobdiff_plain/2624270e11562445ceb31bc15a86e092548fd772..08171f79fc8271d1e8fbb829af4f64c6695c670d:/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 cf2290882..58ee675f0 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 @@ -25,6 +25,7 @@ #include #include #include +#include #define MAX_VLANS 16 #define MAX_PORTS 9 @@ -40,10 +41,12 @@ typedef char bitnum; #define REG_SUPP(x) (((x).m != ((u16)-1)) && ((x).p != (u16)-1)) +struct ip175c_state; + /*********** CONSTANTS ***********/ struct register_mappings { char *NAME; - u16 MODEL_NO; // compare to bits 4-9 of MII register 0,3. + u16 MODEL_NO; // Compare to bits 4-9 of MII register 0,3. bitnum NUM_PORTS; bitnum CPU_PORT; @@ -96,8 +99,17 @@ 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 (*update_state)(struct ip175c_state *state); + int (*set_vlan_mode)(struct ip175c_state *state); + int (*reset)(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 +152,9 @@ static const struct register_mappings IP178C = { .MII_REGISTER_EN = NOTSUPPORTED, + .update_state = ip175c_update_state, + .set_vlan_mode = ip175c_set_vlan_mode, + .reset = ip175c_do_reset, }; static const struct register_mappings IP175C = { @@ -184,6 +199,9 @@ static const struct register_mappings IP175C = { .MII_REGISTER_EN = NOTSUPPORTED, + .update_state = ip175c_update_state, + .set_vlan_mode = ip175c_set_vlan_mode, + .reset = ip175c_do_reset, }; static const struct register_mappings IP175A = { @@ -201,11 +219,8 @@ static const struct register_mappings IP175A = { .SIMPLE_VLAN_REGISTERS = 0, - // Register 19-21 documentation is missing/contradictory. - // For registers 19-21 ports need to be: even numbers to MSB, odd to LSB. - // This contradicts text for ROM registers, but follows logic of CoS bits. - - .VLAN_LOOKUP_REG = {0,19},// +N/2 + // Only programmable via EEPROM + .VLAN_LOOKUP_REG = NOTSUPPORTED,// +N/2 .VLAN_LOOKUP_REG_5 = NOTSUPPORTED, .VLAN_LOOKUP_EVEN_BIT = {8,9,10,11,12,-1,-1,-1,-1}, .VLAN_LOOKUP_ODD_BIT = {0,1,2,3,4,-1,-1,-1,-1}, @@ -231,9 +246,59 @@ static const struct register_mappings IP175A = { .MII_REGISTER_EN = {0, 18}, .MII_REGISTER_EN_BIT = 7, + + .update_state = ip175c_update_state, + .set_vlan_mode = ip175c_set_vlan_mode, + .reset = ip175c_do_reset, }; +static int ip175d_update_state(struct ip175c_state *state); +static int ip175d_set_vlan_mode(struct ip175c_state *state); +static int ip175d_reset(struct ip175c_state *state); + +static const struct register_mappings IP175D = { + .NAME = "IP175D", + .MODEL_NO = 0x18, + + // The IP175D has a completely different interface, so we leave most + // of the registers undefined and switch to different code paths. + + .VLAN_DEFAULT_TAG_REG = { + NOTSUPPORTED,NOTSUPPORTED,NOTSUPPORTED,NOTSUPPORTED, + NOTSUPPORTED,NOTSUPPORTED,NOTSUPPORTED,NOTSUPPORTED, + }, + + .ADD_TAG_REG = NOTSUPPORTED, + .REMOVE_TAG_REG = NOTSUPPORTED, + + .SIMPLE_VLAN_REGISTERS = 0, + + .VLAN_LOOKUP_REG = NOTSUPPORTED, + .VLAN_LOOKUP_REG_5 = NOTSUPPORTED, + .TAG_VLAN_MASK_REG = NOTSUPPORTED, + + .RESET_VAL = 0x175D, + .RESET_REG = {20,2}, + .MODE_REG = NOTSUPPORTED, + + .ROUTER_CONTROL_REG = NOTSUPPORTED, + .ROUTER_EN_BIT = -1, + .NUMLAN_GROUPS_BIT = -1, + + .VLAN_CONTROL_REG = NOTSUPPORTED, + .TAG_VLAN_BIT = -1, + + .NUM_PORTS = 6, + .CPU_PORT = 5, + + .MII_REGISTER_EN = NOTSUPPORTED, + + .update_state = ip175d_update_state, + .set_vlan_mode = ip175d_set_vlan_mode, + .reset = ip175d_reset, +}; + struct ip175c_state { struct switch_dev dev; struct mii_bus *mii_bus; @@ -248,13 +313,17 @@ 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 /proc */ + reg proc_mii; // phy/reg for the low level register access via swconfig char buf[80]; }; + static int ip_phy_read(struct ip175c_state *state, int port, int reg) { int val = mdiobus_read(state->mii_bus, port, reg); @@ -267,7 +336,6 @@ static int ip_phy_read(struct ip175c_state *state, int port, int reg) return val; } - static int ip_phy_write(struct ip175c_state *state, int port, int reg, u16 val) { int err; @@ -281,7 +349,6 @@ static int ip_phy_write(struct ip175c_state *state, int port, int reg, u16 val) return err; } - static int ip_phy_write_masked(struct ip175c_state *state, int port, int reg, unsigned int mask, unsigned int data) { int val = ip_phy_read(state, port, reg); @@ -310,6 +377,7 @@ static int setPhy(struct ip175c_state *state, reg mii, u16 value) return 0; } + /** * These two macros are to simplify the mapping of logical bits to the bits in hardware. * NOTE: these macros will return if there is an error! @@ -344,186 +412,53 @@ static int setPhy(struct ip175c_state *state, reg mii, u16 value) return val; \ } while (0) + static int get_model(struct ip175c_state *state) { - reg oui_id_reg = {0, 2}; - int oui_id; - reg model_no_reg = {0, 3}; - int model_no, model_no_orig; - - // 175 and 178 have the same oui ID. - reg oui_id_reg_178c = {5, 2}; // returns error on IP175C. - int is_178c = 0; - - oui_id = getPhy(state, oui_id_reg); - if (oui_id != 0x0243) { - // non - return -ENODEV; // Not a IC+ chip. - } - oui_id = getPhy(state, oui_id_reg_178c); - if (oui_id == 0x0243) { - is_178c = 1; - } + int id1, id2; + int oui_id, model_no, rev_no, chip_no; + + id1 = ip_phy_read(state, 0, 2); + id2 = ip_phy_read(state, 0, 3); + oui_id = (id1 << 6) | ((id2 >> 10) & 0x3f); + model_no = (id2 >> 4) & 0x3f; + rev_no = id2 & 0xf; + pr_debug("IP175C: Identified oui=%06x model=%02x rev=%X\n", oui_id, model_no, rev_no); - model_no_orig = getPhy(state, model_no_reg); - if (model_no_orig < 0) { + if (oui_id != 0x0090c3) // No other oui_id should have reached us anyway return -ENODEV; - } - model_no = model_no_orig >> 4; // shift out revision number. - model_no &= 0x3f; // only take the model number (low 6 bits). + if (model_no == IP175A.MODEL_NO) { state->regs = &IP175A; } else if (model_no == IP175C.MODEL_NO) { - if (is_178c) { + /* + * Several models share the same model_no: + * 178C has more PHYs, so we try whether the device responds to a read from PHY5 + * 175D has a new chip ID register + * 175C has neither + */ + if (ip_phy_read(state, 5, 2) == 0x0243) { state->regs = &IP178C; } else { - state->regs = &IP175C; - } - } else { - printk(KERN_WARNING "ip175c: Found an unknown IC+ switch with model number %02Xh.\n", model_no_orig); - return -EPERM; - } - return 0; -} - -/** Get only the vlan and router flags on the router **/ -static int get_flags(struct ip175c_state *state) -{ - int val; - - state->router_mode = 0; - state->vlan_enabled = -1; // hack - state->num_vlans = 0; - - if (!REG_SUPP(state->regs->ROUTER_CONTROL_REG)) { - return 0; // not an error if it doesn't support enable vlan. - } - - val = getPhy(state, state->regs->ROUTER_CONTROL_REG); - if (val < 0) { - return val; - } - if (state->regs->ROUTER_EN_BIT >= 0) - state->router_mode = ((val>>state->regs->ROUTER_EN_BIT) & 1); - - if (state->regs->NUMLAN_GROUPS_BIT >= 0) { - state->num_vlans = (val >> state->regs->NUMLAN_GROUPS_BIT); - state->num_vlans &= (state->regs->NUMLAN_GROUPS_MAX-1); - state->num_vlans+=1; // does not include WAN. - } - - - val = getPhy(state, state->regs->VLAN_CONTROL_REG); - if (val < 0) { - return 0; - } - if (state->regs->TAG_VLAN_BIT >= 0) - state->vlan_enabled = ((val>>state->regs->TAG_VLAN_BIT) & 1); - - return 0; -} -/** Get all state variables for VLAN mappings and port-based tagging. **/ -static int get_state(struct ip175c_state *state) -{ - int i, j; - int ret; - ret = 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, - state->regs->ADD_TAG_REG, state->regs->ADD_TAG_BIT); - - if (state->vlan_enabled == -1) { - // not sure how to get this... - state->vlan_enabled = (state->remove_tag || state->add_tag); - } - - 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; - } - } - - if (REG_SUPP(addr)) { - GET_PORT_BITS(state, state->ports[j].shareports, addr, bit_lookup); - } - } - } else { - for (j=0; jports[j].shareports = 0xff; - } - } - - for (i=0; iregs->VLAN_DEFAULT_TAG_REG[i])) { - int val = getPhy(state, state->regs->VLAN_DEFAULT_TAG_REG[i]); - if (val < 0) { - return val; - } - state->ports[i].pvid = val; - } else { - state->ports[i].pvid = 0; - } - } - - 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; - if (state->regs->SIMPLE_VLAN_REGISTERS) { - addr.m += j; + chip_no = ip_phy_read(state, 20, 0); + pr_debug("IP175C: Chip ID register reads %04x\n", chip_no); + if (chip_no == 0x175d) { + state->regs = &IP175D; } else { - addr.m += j/2; + state->regs = &IP175C; } - GET_PORT_BITS(state, state->vlan_ports[j], addr, bit_lookup); } } else { - for (j=0; jvlan_ports[j] = 0; - for (i=0; iregs->NUM_PORTS; i++) { - if ((state->ports[i].pvid == j) || - (state->ports[i].pvid == 0)) { - state->vlan_ports[j] |= (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; @@ -571,57 +506,56 @@ 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; + + 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) { - state->num_vlans = i+1; //hack -- we need to store the "set" vlans somewhere... + if (state->vlans[i].ports != 0) { + state->num_vlans = i+1; // Hack -- we need to store the "set" vlans somewhere... } } - - for (i=0; iregs->NUM_PORTS; i++) { unsigned int portmask = (1<vlan_enabled) { - // share with everybody! + // Share with everybody! state->ports[i].shareports = (1<regs->NUM_PORTS)-1; continue; } 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 ip175c_update_state(state); +} + +/*** Low-level functions for IP175D ***/ + +static int ip175d_update_state(struct ip175c_state *state) +{ + unsigned int filter_mask = 0; + unsigned int ports[16], add[16], rem[16]; + int i, j; + int err = 0; + + for (i = 0; i < 16; i++) { + ports[i] = 0; + add[i] = 0; + rem[i] = 0; + if (!state->vlan_enabled) { + err |= ip_phy_write(state, 22, 14+i, i+1); // default tags + ports[i] = 0x3f; + continue; + } + if (!state->vlans[i].tag) { + // Reset the filter + err |= ip_phy_write(state, 22, 14+i, 0); // tag + continue; + } + filter_mask |= 1 << i; + err |= ip_phy_write(state, 22, 14+i, state->vlans[i].tag); + ports[i] = state->vlans[i].ports; + for (j = 0; j < 6; j++) { + if (ports[i] & (1 << j)) { + if (state->add_tag & (1 << j)) + add[i] |= 1 << j; + if (state->remove_tag & (1 << j)) + rem[i] |= 1 << j; + } + } + } + + // Port masks, tag adds and removals + for (i = 0; i < 8; i++) { + err |= ip_phy_write(state, 23, i, ports[2*i] | (ports[2*i+1] << 8)); + err |= ip_phy_write(state, 23, 8+i, add[2*i] | (add[2*i+1] << 8)); + err |= ip_phy_write(state, 23, 16+i, rem[2*i] | (rem[2*i+1] << 8)); + } + err |= ip_phy_write(state, 22, 10, filter_mask); + + // Default VLAN tag for each port + for (i = 0; i < 6; i++) + err |= ip_phy_write(state, 22, 4+i, state->vlans[state->ports[i].pvid].tag); + + return (err ? -EIO : 0); +} + +static int ip175d_set_vlan_mode(struct ip175c_state *state) +{ + int i; + int err = 0; + + if (state->vlan_enabled) { + // VLAN classification rules: tag-based VLANs, use VID to classify, + // drop packets that cannot be classified. + err |= ip_phy_write_masked(state, 22, 0, 0x3fff, 0x003f); + + // Ingress rules: CFI=1 dropped, null VID is untagged, VID=1 passed, + // VID=0xfff discarded, admin both tagged and untagged, ingress + // filters enabled. + err |= ip_phy_write_masked(state, 22, 1, 0x0fff, 0x0c3f); + + // Egress rules: IGMP processing off, keep VLAN header off + err |= ip_phy_write_masked(state, 22, 2, 0x0fff, 0x0000); + } else { + // VLAN classification rules: everything off & clear table + err |= ip_phy_write_masked(state, 22, 0, 0xbfff, 0x8000); + + // Ingress and egress rules: set to defaults + err |= ip_phy_write_masked(state, 22, 1, 0x0fff, 0x0c3f); + err |= ip_phy_write_masked(state, 22, 2, 0x0fff, 0x0000); + } + + // Reset default VLAN for each port to 0 + for (i = 0; i < 6; i++) + state->ports[i].pvid = 0; + + err |= ip175d_update_state(state); + + return (err ? -EIO : 0); +} + +static int ip175d_reset(struct ip175c_state *state) +{ + int err = 0; + + // Disable the special tagging mode + err |= ip_phy_write_masked(state, 21, 22, 0x0003, 0x0000); + + // Set 802.1q protocol type + err |= ip_phy_write(state, 22, 3, 0x8100); + + state->vlan_enabled = 0; + err |= ip175d_set_vlan_mode(state); + + return (err ? -EIO : 0); +} + +/*** High-level functions ***/ + static int ip175c_get_enable_vlan(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val) { struct ip175c_state *state = dev->priv; - int err; - err = 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); - if (err < 0) - return err; enable = val->value.i; - if (state->vlan_enabled == enable) { - // do not change any state. + // Do not change any state. return 0; } 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; - - for (i = 0; i < MAX_VLANS; i++) - state->vlan_ports[i] = 0x0; + ip175c_reset_vlan_config(state); - 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) { struct ip175c_state *state = dev->priv; - int err; int b; int ind; unsigned int ports; @@ -732,11 +781,7 @@ 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); - 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) { @@ -758,42 +803,31 @@ static int ip175c_set_ports(struct switch_dev *dev, struct switch_val *val) { struct ip175c_state *state = dev->priv; int i; - int err; if (val->port_vlan >= dev->vlans || val->port_vlan < 0) return -EINVAL; - err = 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) { struct ip175c_state *state = dev->priv; - int err; - err = get_flags(state); - if (err < 0) - return err; - - if (REG_SUPP(state->regs->MII_REGISTER_EN)){ + if (REG_SUPP(state->regs->MII_REGISTER_EN)) { int val = getPhy(state, state->regs->MII_REGISTER_EN); if (val < 0) { return val; @@ -809,29 +843,20 @@ static int ip175c_reset(struct switch_dev *dev) struct ip175c_state *state = dev->priv; int i, err; - err = get_flags(state); - if (err < 0) - return err; - if (REG_SUPP(state->regs->RESET_REG)) { err = setPhy(state, state->regs->RESET_REG, state->regs->RESET_VAL); if (err < 0) return err; err = getPhy(state, state->regs->RESET_REG); - /* data sheet specifies reset period is 2 msec - (don't see any mention of the 2ms delay in the IP178C spec, only - in IP175C, but it can't hurt.) */ + /* + * Data sheet specifies reset period to be 2 msec. + * (I don't see any mention of the 2ms delay in the IP178C spec, only + * in IP175C, but it can't hurt.) + */ 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); @@ -839,18 +864,16 @@ static int ip175c_reset(struct switch_dev *dev) return err; } - return 0; + state->router_mode = 0; + state->vlan_enabled = 0; + ip175c_reset_vlan_config(state); + + return state->regs->reset(state); } -/*! get the current register number */ static int ip175c_get_tagged(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val) { struct ip175c_state *state = dev->priv; - int err; - - err = get_state(state); - if (err < 0) - return err; if (state->add_tag & (1<port_vlan)) { if (state->remove_tag & (1<port_vlan)) @@ -866,15 +889,9 @@ static int ip175c_get_tagged(struct switch_dev *dev, const struct switch_attr *a return 0; } -/*! set a new register address for low level access to registers */ static int ip175c_set_tagged(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val) { struct ip175c_state *state = dev->priv; - int err; - - err = get_state(state); - if (err < 0) - return err; state->add_tag &= ~(1<port_vlan); state->remove_tag &= ~(1<port_vlan); @@ -884,18 +901,10 @@ 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); } - -/* low level /proc procedures */ - -/*! get the current phy address */ +/** Get the current phy address */ static int ip175c_get_phy(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val) { struct ip175c_state *state = dev->priv; @@ -904,7 +913,7 @@ static int ip175c_get_phy(struct switch_dev *dev, const struct switch_attr *attr return 0; } -/*! set a new phy address for low level access to registers */ +/** Set a new phy address for low level access to registers */ static int ip175c_set_phy(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val) { struct ip175c_state *state = dev->priv; @@ -917,7 +926,7 @@ static int ip175c_set_phy(struct switch_dev *dev, const struct switch_attr *attr return 0; } -/*! get the current register number */ +/** Get the current register number */ static int ip175c_get_reg(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val) { struct ip175c_state *state = dev->priv; @@ -926,7 +935,7 @@ static int ip175c_get_reg(struct switch_dev *dev, const struct switch_attr *attr return 0; } -/*! set a new register address for low level access to registers */ +/** Set a new register address for low level access to registers */ static int ip175c_set_reg(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val) { struct ip175c_state *state = dev->priv; @@ -939,7 +948,7 @@ static int ip175c_set_reg(struct switch_dev *dev, const struct switch_attr *attr return 0; } -/*! get the register content of state->proc_mii */ +/** Get the register content of state->proc_mii */ static int ip175c_get_val(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val) { struct ip175c_state *state = dev->priv; @@ -955,11 +964,11 @@ static int ip175c_get_val(struct switch_dev *dev, const struct switch_attr *attr } } -/*! write a value to the register defined by phy/reg above */ +/** Write a value to the register defined by phy/reg above */ 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)) { @@ -971,10 +980,37 @@ static int ip175c_set_val(struct switch_dev *dev, const struct switch_attr *attr static int ip175c_read_name(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val) { struct ip175c_state *state = dev->priv; - val->value.s = state->regs->NAME; // just a const pointer, won't be freed by swconfig. + val->value.s = state->regs->NAME; // Just a const pointer, won't be freed by swconfig. 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) { @@ -994,7 +1030,7 @@ static int ip175c_set_port_speed(struct switch_dev *dev, const struct switch_att speed = 1; } - /* can't set speed for cpu port */ + /* Can't set speed for cpu port */ if (nr == state->regs->CPU_PORT) return -EINVAL; @@ -1040,7 +1076,6 @@ static int ip175c_get_port_speed(struct switch_dev *dev, const struct switch_att return 0; } - static int ip175c_get_port_status(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val) { struct ip175c_state *state = dev->priv; @@ -1097,12 +1132,11 @@ static int ip175c_set_pvid(struct switch_dev *dev, int port, int val) { struct ip175c_state *state = dev->priv; - state->ports[port].pvid = val; - - if (!REG_SUPP(state->regs->VLAN_DEFAULT_TAG_REG[port])) - return 0; + if (val < 0 || val >= MAX_VLANS) + return -EINVAL; - return setPhy(state, state->regs->VLAN_DEFAULT_TAG_REG[port], val); + state->ports[port].pvid = val; + return state->regs->update_state(state); } @@ -1122,6 +1156,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, @@ -1143,7 +1181,7 @@ static const struct switch_attr ip175c_global[] = { [IP175C_REGISTER_PHY] = { .id = IP175C_REGISTER_PHY, .type = SWITCH_TYPE_INT, - .description = "Direct register access: set phy (0-4, or 29,30,31)", + .description = "Direct register access: set PHY (0-4, or 29,30,31)", .name = "phy", .get = ip175c_get_phy, .set = ip175c_set_phy, @@ -1151,7 +1189,7 @@ static const struct switch_attr ip175c_global[] = { [IP175C_REGISTER_MII] = { .id = IP175C_REGISTER_MII, .type = SWITCH_TYPE_INT, - .description = "Direct register access: set mii number (0-31)", + .description = "Direct register access: set MII register number (0-31)", .name = "reg", .get = ip175c_get_reg, .set = ip175c_set_reg, @@ -1167,6 +1205,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[] = { @@ -1202,7 +1248,7 @@ static int ip175c_probe(struct phy_device *pdev) struct switch_dev *dev; int err; - /* we only attach to PHY 0, but use all available PHYs */ + /* We only attach to PHY 0, but use all available PHYs */ if (pdev->addr != 0) return -ENODEV; @@ -1238,6 +1284,7 @@ static int ip175c_probe(struct phy_device *pdev) dev->ports = state->regs->NUM_PORTS; dev->name = state->regs->NAME; + pr_info("IP175C: Found %s at %s\n", dev->name, dev_name(&pdev->dev)); return 0; error: @@ -1259,6 +1306,11 @@ static int ip175c_config_init(struct phy_device *pdev) ip175c_reset(&state->dev); state->registered = true; + + pdev->state = PHY_RUNNING; + pdev->speed = SPEED_100; + pdev->duplex = DUPLEX_FULL; + pdev->pause = pdev->asym_pause = 0; netif_carrier_on(pdev->attached_dev); return 0; @@ -1280,16 +1332,13 @@ static int ip175c_config_aneg(struct phy_device *pdev) static int ip175c_read_status(struct phy_device *pdev) { - pdev->speed = SPEED_100; - pdev->duplex = DUPLEX_FULL; - pdev->pause = pdev->asym_pause = 0; return 0; } static struct phy_driver ip175c_driver = { .name = "IC+ IP175C", - .phy_id = 0x02430d80, - .phy_id_mask = 0x0ffffff0, + .phy_id = 0x02430c00, + .phy_id_mask = 0x0ffffc00, .features = PHY_BASIC_FEATURES, .probe = ip175c_probe, .remove = ip175c_remove, @@ -1336,4 +1385,3 @@ MODULE_LICENSE("GPL"); module_init(ip175c_init); module_exit(ip175c_exit); -