156051948SVladimir Oltean // SPDX-License-Identifier: GPL-2.0 256051948SVladimir Oltean /* Copyright 2019 NXP Semiconductors 356051948SVladimir Oltean */ 456051948SVladimir Oltean #include <uapi/linux/if_bridge.h> 5*bdeced75SVladimir Oltean #include <soc/mscc/ocelot_qsys.h> 6*bdeced75SVladimir Oltean #include <soc/mscc/ocelot_sys.h> 7*bdeced75SVladimir Oltean #include <soc/mscc/ocelot_dev.h> 8*bdeced75SVladimir Oltean #include <soc/mscc/ocelot_ana.h> 956051948SVladimir Oltean #include <soc/mscc/ocelot.h> 10c0bcf537SYangbo Lu #include <linux/packing.h> 1156051948SVladimir Oltean #include <linux/module.h> 12*bdeced75SVladimir Oltean #include <linux/of_net.h> 1356051948SVladimir Oltean #include <linux/pci.h> 1456051948SVladimir Oltean #include <linux/of.h> 1556051948SVladimir Oltean #include <net/dsa.h> 1656051948SVladimir Oltean #include "felix.h" 1756051948SVladimir Oltean 1856051948SVladimir Oltean static enum dsa_tag_protocol felix_get_tag_protocol(struct dsa_switch *ds, 1956051948SVladimir Oltean int port) 2056051948SVladimir Oltean { 2156051948SVladimir Oltean return DSA_TAG_PROTO_OCELOT; 2256051948SVladimir Oltean } 2356051948SVladimir Oltean 2456051948SVladimir Oltean static int felix_set_ageing_time(struct dsa_switch *ds, 2556051948SVladimir Oltean unsigned int ageing_time) 2656051948SVladimir Oltean { 2756051948SVladimir Oltean struct ocelot *ocelot = ds->priv; 2856051948SVladimir Oltean 2956051948SVladimir Oltean ocelot_set_ageing_time(ocelot, ageing_time); 3056051948SVladimir Oltean 3156051948SVladimir Oltean return 0; 3256051948SVladimir Oltean } 3356051948SVladimir Oltean 3456051948SVladimir Oltean static int felix_fdb_dump(struct dsa_switch *ds, int port, 3556051948SVladimir Oltean dsa_fdb_dump_cb_t *cb, void *data) 3656051948SVladimir Oltean { 3756051948SVladimir Oltean struct ocelot *ocelot = ds->priv; 3856051948SVladimir Oltean 3956051948SVladimir Oltean return ocelot_fdb_dump(ocelot, port, cb, data); 4056051948SVladimir Oltean } 4156051948SVladimir Oltean 4256051948SVladimir Oltean static int felix_fdb_add(struct dsa_switch *ds, int port, 4356051948SVladimir Oltean const unsigned char *addr, u16 vid) 4456051948SVladimir Oltean { 4556051948SVladimir Oltean struct ocelot *ocelot = ds->priv; 4656051948SVladimir Oltean bool vlan_aware; 4756051948SVladimir Oltean 4856051948SVladimir Oltean vlan_aware = dsa_port_is_vlan_filtering(dsa_to_port(ds, port)); 4956051948SVladimir Oltean 5056051948SVladimir Oltean return ocelot_fdb_add(ocelot, port, addr, vid, vlan_aware); 5156051948SVladimir Oltean } 5256051948SVladimir Oltean 5356051948SVladimir Oltean static int felix_fdb_del(struct dsa_switch *ds, int port, 5456051948SVladimir Oltean const unsigned char *addr, u16 vid) 5556051948SVladimir Oltean { 5656051948SVladimir Oltean struct ocelot *ocelot = ds->priv; 5756051948SVladimir Oltean 5856051948SVladimir Oltean return ocelot_fdb_del(ocelot, port, addr, vid); 5956051948SVladimir Oltean } 6056051948SVladimir Oltean 6156051948SVladimir Oltean static void felix_bridge_stp_state_set(struct dsa_switch *ds, int port, 6256051948SVladimir Oltean u8 state) 6356051948SVladimir Oltean { 6456051948SVladimir Oltean struct ocelot *ocelot = ds->priv; 6556051948SVladimir Oltean 6656051948SVladimir Oltean return ocelot_bridge_stp_state_set(ocelot, port, state); 6756051948SVladimir Oltean } 6856051948SVladimir Oltean 6956051948SVladimir Oltean static int felix_bridge_join(struct dsa_switch *ds, int port, 7056051948SVladimir Oltean struct net_device *br) 7156051948SVladimir Oltean { 7256051948SVladimir Oltean struct ocelot *ocelot = ds->priv; 7356051948SVladimir Oltean 7456051948SVladimir Oltean return ocelot_port_bridge_join(ocelot, port, br); 7556051948SVladimir Oltean } 7656051948SVladimir Oltean 7756051948SVladimir Oltean static void felix_bridge_leave(struct dsa_switch *ds, int port, 7856051948SVladimir Oltean struct net_device *br) 7956051948SVladimir Oltean { 8056051948SVladimir Oltean struct ocelot *ocelot = ds->priv; 8156051948SVladimir Oltean 8256051948SVladimir Oltean ocelot_port_bridge_leave(ocelot, port, br); 8356051948SVladimir Oltean } 8456051948SVladimir Oltean 8556051948SVladimir Oltean /* This callback needs to be present */ 8656051948SVladimir Oltean static int felix_vlan_prepare(struct dsa_switch *ds, int port, 8756051948SVladimir Oltean const struct switchdev_obj_port_vlan *vlan) 8856051948SVladimir Oltean { 8956051948SVladimir Oltean return 0; 9056051948SVladimir Oltean } 9156051948SVladimir Oltean 9256051948SVladimir Oltean static int felix_vlan_filtering(struct dsa_switch *ds, int port, bool enabled) 9356051948SVladimir Oltean { 9456051948SVladimir Oltean struct ocelot *ocelot = ds->priv; 9556051948SVladimir Oltean 9656051948SVladimir Oltean ocelot_port_vlan_filtering(ocelot, port, enabled); 9756051948SVladimir Oltean 9856051948SVladimir Oltean return 0; 9956051948SVladimir Oltean } 10056051948SVladimir Oltean 10156051948SVladimir Oltean static void felix_vlan_add(struct dsa_switch *ds, int port, 10256051948SVladimir Oltean const struct switchdev_obj_port_vlan *vlan) 10356051948SVladimir Oltean { 10456051948SVladimir Oltean struct ocelot *ocelot = ds->priv; 10556051948SVladimir Oltean u16 vid; 10656051948SVladimir Oltean int err; 10756051948SVladimir Oltean 10856051948SVladimir Oltean for (vid = vlan->vid_begin; vid <= vlan->vid_end; vid++) { 10956051948SVladimir Oltean err = ocelot_vlan_add(ocelot, port, vid, 11056051948SVladimir Oltean vlan->flags & BRIDGE_VLAN_INFO_PVID, 11156051948SVladimir Oltean vlan->flags & BRIDGE_VLAN_INFO_UNTAGGED); 11256051948SVladimir Oltean if (err) { 11356051948SVladimir Oltean dev_err(ds->dev, "Failed to add VLAN %d to port %d: %d\n", 11456051948SVladimir Oltean vid, port, err); 11556051948SVladimir Oltean return; 11656051948SVladimir Oltean } 11756051948SVladimir Oltean } 11856051948SVladimir Oltean } 11956051948SVladimir Oltean 12056051948SVladimir Oltean static int felix_vlan_del(struct dsa_switch *ds, int port, 12156051948SVladimir Oltean const struct switchdev_obj_port_vlan *vlan) 12256051948SVladimir Oltean { 12356051948SVladimir Oltean struct ocelot *ocelot = ds->priv; 12456051948SVladimir Oltean u16 vid; 12556051948SVladimir Oltean int err; 12656051948SVladimir Oltean 12756051948SVladimir Oltean for (vid = vlan->vid_begin; vid <= vlan->vid_end; vid++) { 12856051948SVladimir Oltean err = ocelot_vlan_del(ocelot, port, vid); 12956051948SVladimir Oltean if (err) { 13056051948SVladimir Oltean dev_err(ds->dev, "Failed to remove VLAN %d from port %d: %d\n", 13156051948SVladimir Oltean vid, port, err); 13256051948SVladimir Oltean return err; 13356051948SVladimir Oltean } 13456051948SVladimir Oltean } 13556051948SVladimir Oltean return 0; 13656051948SVladimir Oltean } 13756051948SVladimir Oltean 13856051948SVladimir Oltean static int felix_port_enable(struct dsa_switch *ds, int port, 13956051948SVladimir Oltean struct phy_device *phy) 14056051948SVladimir Oltean { 14156051948SVladimir Oltean struct ocelot *ocelot = ds->priv; 14256051948SVladimir Oltean 14356051948SVladimir Oltean ocelot_port_enable(ocelot, port, phy); 14456051948SVladimir Oltean 14556051948SVladimir Oltean return 0; 14656051948SVladimir Oltean } 14756051948SVladimir Oltean 14856051948SVladimir Oltean static void felix_port_disable(struct dsa_switch *ds, int port) 14956051948SVladimir Oltean { 15056051948SVladimir Oltean struct ocelot *ocelot = ds->priv; 15156051948SVladimir Oltean 15256051948SVladimir Oltean return ocelot_port_disable(ocelot, port); 15356051948SVladimir Oltean } 15456051948SVladimir Oltean 155*bdeced75SVladimir Oltean static void felix_phylink_validate(struct dsa_switch *ds, int port, 156*bdeced75SVladimir Oltean unsigned long *supported, 157*bdeced75SVladimir Oltean struct phylink_link_state *state) 158*bdeced75SVladimir Oltean { 159*bdeced75SVladimir Oltean struct ocelot *ocelot = ds->priv; 160*bdeced75SVladimir Oltean struct ocelot_port *ocelot_port = ocelot->ports[port]; 161*bdeced75SVladimir Oltean __ETHTOOL_DECLARE_LINK_MODE_MASK(mask) = { 0, }; 162*bdeced75SVladimir Oltean 163*bdeced75SVladimir Oltean if (state->interface != PHY_INTERFACE_MODE_NA && 164*bdeced75SVladimir Oltean state->interface != ocelot_port->phy_mode) { 165*bdeced75SVladimir Oltean bitmap_zero(supported, __ETHTOOL_LINK_MODE_MASK_NBITS); 166*bdeced75SVladimir Oltean return; 167*bdeced75SVladimir Oltean } 168*bdeced75SVladimir Oltean 169*bdeced75SVladimir Oltean /* No half-duplex. */ 170*bdeced75SVladimir Oltean phylink_set_port_modes(mask); 171*bdeced75SVladimir Oltean phylink_set(mask, Autoneg); 172*bdeced75SVladimir Oltean phylink_set(mask, Pause); 173*bdeced75SVladimir Oltean phylink_set(mask, Asym_Pause); 174*bdeced75SVladimir Oltean if (state->interface != PHY_INTERFACE_MODE_2500BASEX) { 175*bdeced75SVladimir Oltean phylink_set(mask, 10baseT_Full); 176*bdeced75SVladimir Oltean phylink_set(mask, 100baseT_Full); 177*bdeced75SVladimir Oltean phylink_set(mask, 1000baseT_Full); 178*bdeced75SVladimir Oltean } 179*bdeced75SVladimir Oltean /* The internal ports that run at 2.5G are overclocked GMII */ 180*bdeced75SVladimir Oltean if (state->interface == PHY_INTERFACE_MODE_GMII || 181*bdeced75SVladimir Oltean state->interface == PHY_INTERFACE_MODE_2500BASEX || 182*bdeced75SVladimir Oltean state->interface == PHY_INTERFACE_MODE_USXGMII) { 183*bdeced75SVladimir Oltean phylink_set(mask, 2500baseT_Full); 184*bdeced75SVladimir Oltean phylink_set(mask, 2500baseX_Full); 185*bdeced75SVladimir Oltean } 186*bdeced75SVladimir Oltean 187*bdeced75SVladimir Oltean bitmap_and(supported, supported, mask, 188*bdeced75SVladimir Oltean __ETHTOOL_LINK_MODE_MASK_NBITS); 189*bdeced75SVladimir Oltean bitmap_and(state->advertising, state->advertising, mask, 190*bdeced75SVladimir Oltean __ETHTOOL_LINK_MODE_MASK_NBITS); 191*bdeced75SVladimir Oltean } 192*bdeced75SVladimir Oltean 193*bdeced75SVladimir Oltean static int felix_phylink_mac_pcs_get_state(struct dsa_switch *ds, int port, 194*bdeced75SVladimir Oltean struct phylink_link_state *state) 195*bdeced75SVladimir Oltean { 196*bdeced75SVladimir Oltean struct ocelot *ocelot = ds->priv; 197*bdeced75SVladimir Oltean struct felix *felix = ocelot_to_felix(ocelot); 198*bdeced75SVladimir Oltean 199*bdeced75SVladimir Oltean if (felix->info->pcs_link_state) 200*bdeced75SVladimir Oltean felix->info->pcs_link_state(ocelot, port, state); 201*bdeced75SVladimir Oltean 202*bdeced75SVladimir Oltean return 0; 203*bdeced75SVladimir Oltean } 204*bdeced75SVladimir Oltean 205*bdeced75SVladimir Oltean static void felix_phylink_mac_config(struct dsa_switch *ds, int port, 206*bdeced75SVladimir Oltean unsigned int link_an_mode, 207*bdeced75SVladimir Oltean const struct phylink_link_state *state) 208*bdeced75SVladimir Oltean { 209*bdeced75SVladimir Oltean struct ocelot *ocelot = ds->priv; 210*bdeced75SVladimir Oltean struct ocelot_port *ocelot_port = ocelot->ports[port]; 211*bdeced75SVladimir Oltean struct felix *felix = ocelot_to_felix(ocelot); 212*bdeced75SVladimir Oltean u32 mac_fc_cfg; 213*bdeced75SVladimir Oltean 214*bdeced75SVladimir Oltean /* Take port out of reset by clearing the MAC_TX_RST, MAC_RX_RST and 215*bdeced75SVladimir Oltean * PORT_RST bits in CLOCK_CFG 216*bdeced75SVladimir Oltean */ 217*bdeced75SVladimir Oltean ocelot_port_writel(ocelot_port, DEV_CLOCK_CFG_LINK_SPEED(state->speed), 218*bdeced75SVladimir Oltean DEV_CLOCK_CFG); 219*bdeced75SVladimir Oltean 220*bdeced75SVladimir Oltean /* Flow control. Link speed is only used here to evaluate the time 221*bdeced75SVladimir Oltean * specification in incoming pause frames. 222*bdeced75SVladimir Oltean */ 223*bdeced75SVladimir Oltean mac_fc_cfg = SYS_MAC_FC_CFG_FC_LINK_SPEED(state->speed); 224*bdeced75SVladimir Oltean if (state->pause & MLO_PAUSE_RX) 225*bdeced75SVladimir Oltean mac_fc_cfg |= SYS_MAC_FC_CFG_RX_FC_ENA; 226*bdeced75SVladimir Oltean if (state->pause & MLO_PAUSE_TX) 227*bdeced75SVladimir Oltean mac_fc_cfg |= SYS_MAC_FC_CFG_TX_FC_ENA | 228*bdeced75SVladimir Oltean SYS_MAC_FC_CFG_PAUSE_VAL_CFG(0xffff) | 229*bdeced75SVladimir Oltean SYS_MAC_FC_CFG_FC_LATENCY_CFG(0x7) | 230*bdeced75SVladimir Oltean SYS_MAC_FC_CFG_ZERO_PAUSE_ENA; 231*bdeced75SVladimir Oltean ocelot_write_rix(ocelot, mac_fc_cfg, SYS_MAC_FC_CFG, port); 232*bdeced75SVladimir Oltean 233*bdeced75SVladimir Oltean ocelot_write_rix(ocelot, 0, ANA_POL_FLOWC, port); 234*bdeced75SVladimir Oltean 235*bdeced75SVladimir Oltean if (felix->info->pcs_init) 236*bdeced75SVladimir Oltean felix->info->pcs_init(ocelot, port, link_an_mode, state); 237*bdeced75SVladimir Oltean } 238*bdeced75SVladimir Oltean 239*bdeced75SVladimir Oltean static void felix_phylink_mac_an_restart(struct dsa_switch *ds, int port) 240*bdeced75SVladimir Oltean { 241*bdeced75SVladimir Oltean struct ocelot *ocelot = ds->priv; 242*bdeced75SVladimir Oltean struct felix *felix = ocelot_to_felix(ocelot); 243*bdeced75SVladimir Oltean 244*bdeced75SVladimir Oltean if (felix->info->pcs_an_restart) 245*bdeced75SVladimir Oltean felix->info->pcs_an_restart(ocelot, port); 246*bdeced75SVladimir Oltean } 247*bdeced75SVladimir Oltean 248*bdeced75SVladimir Oltean static void felix_phylink_mac_link_down(struct dsa_switch *ds, int port, 249*bdeced75SVladimir Oltean unsigned int link_an_mode, 250*bdeced75SVladimir Oltean phy_interface_t interface) 251*bdeced75SVladimir Oltean { 252*bdeced75SVladimir Oltean struct ocelot *ocelot = ds->priv; 253*bdeced75SVladimir Oltean struct ocelot_port *ocelot_port = ocelot->ports[port]; 254*bdeced75SVladimir Oltean 255*bdeced75SVladimir Oltean ocelot_port_writel(ocelot_port, 0, DEV_MAC_ENA_CFG); 256*bdeced75SVladimir Oltean ocelot_rmw_rix(ocelot, 0, QSYS_SWITCH_PORT_MODE_PORT_ENA, 257*bdeced75SVladimir Oltean QSYS_SWITCH_PORT_MODE, port); 258*bdeced75SVladimir Oltean } 259*bdeced75SVladimir Oltean 260*bdeced75SVladimir Oltean static void felix_phylink_mac_link_up(struct dsa_switch *ds, int port, 261*bdeced75SVladimir Oltean unsigned int link_an_mode, 262*bdeced75SVladimir Oltean phy_interface_t interface, 263*bdeced75SVladimir Oltean struct phy_device *phydev) 264*bdeced75SVladimir Oltean { 265*bdeced75SVladimir Oltean struct ocelot *ocelot = ds->priv; 266*bdeced75SVladimir Oltean struct ocelot_port *ocelot_port = ocelot->ports[port]; 267*bdeced75SVladimir Oltean 268*bdeced75SVladimir Oltean /* Enable MAC module */ 269*bdeced75SVladimir Oltean ocelot_port_writel(ocelot_port, DEV_MAC_ENA_CFG_RX_ENA | 270*bdeced75SVladimir Oltean DEV_MAC_ENA_CFG_TX_ENA, DEV_MAC_ENA_CFG); 271*bdeced75SVladimir Oltean 272*bdeced75SVladimir Oltean /* Enable receiving frames on the port, and activate auto-learning of 273*bdeced75SVladimir Oltean * MAC addresses. 274*bdeced75SVladimir Oltean */ 275*bdeced75SVladimir Oltean ocelot_write_gix(ocelot, ANA_PORT_PORT_CFG_LEARNAUTO | 276*bdeced75SVladimir Oltean ANA_PORT_PORT_CFG_RECV_ENA | 277*bdeced75SVladimir Oltean ANA_PORT_PORT_CFG_PORTID_VAL(port), 278*bdeced75SVladimir Oltean ANA_PORT_PORT_CFG, port); 279*bdeced75SVladimir Oltean 280*bdeced75SVladimir Oltean /* Core: Enable port for frame transfer */ 281*bdeced75SVladimir Oltean ocelot_write_rix(ocelot, QSYS_SWITCH_PORT_MODE_INGRESS_DROP_MODE | 282*bdeced75SVladimir Oltean QSYS_SWITCH_PORT_MODE_SCH_NEXT_CFG(1) | 283*bdeced75SVladimir Oltean QSYS_SWITCH_PORT_MODE_PORT_ENA, 284*bdeced75SVladimir Oltean QSYS_SWITCH_PORT_MODE, port); 285*bdeced75SVladimir Oltean } 286*bdeced75SVladimir Oltean 28756051948SVladimir Oltean static void felix_get_strings(struct dsa_switch *ds, int port, 28856051948SVladimir Oltean u32 stringset, u8 *data) 28956051948SVladimir Oltean { 29056051948SVladimir Oltean struct ocelot *ocelot = ds->priv; 29156051948SVladimir Oltean 29256051948SVladimir Oltean return ocelot_get_strings(ocelot, port, stringset, data); 29356051948SVladimir Oltean } 29456051948SVladimir Oltean 29556051948SVladimir Oltean static void felix_get_ethtool_stats(struct dsa_switch *ds, int port, u64 *data) 29656051948SVladimir Oltean { 29756051948SVladimir Oltean struct ocelot *ocelot = ds->priv; 29856051948SVladimir Oltean 29956051948SVladimir Oltean ocelot_get_ethtool_stats(ocelot, port, data); 30056051948SVladimir Oltean } 30156051948SVladimir Oltean 30256051948SVladimir Oltean static int felix_get_sset_count(struct dsa_switch *ds, int port, int sset) 30356051948SVladimir Oltean { 30456051948SVladimir Oltean struct ocelot *ocelot = ds->priv; 30556051948SVladimir Oltean 30656051948SVladimir Oltean return ocelot_get_sset_count(ocelot, port, sset); 30756051948SVladimir Oltean } 30856051948SVladimir Oltean 30956051948SVladimir Oltean static int felix_get_ts_info(struct dsa_switch *ds, int port, 31056051948SVladimir Oltean struct ethtool_ts_info *info) 31156051948SVladimir Oltean { 31256051948SVladimir Oltean struct ocelot *ocelot = ds->priv; 31356051948SVladimir Oltean 31456051948SVladimir Oltean return ocelot_get_ts_info(ocelot, port, info); 31556051948SVladimir Oltean } 31656051948SVladimir Oltean 317*bdeced75SVladimir Oltean static int felix_parse_ports_node(struct felix *felix, 318*bdeced75SVladimir Oltean struct device_node *ports_node, 319*bdeced75SVladimir Oltean phy_interface_t *port_phy_modes) 320*bdeced75SVladimir Oltean { 321*bdeced75SVladimir Oltean struct ocelot *ocelot = &felix->ocelot; 322*bdeced75SVladimir Oltean struct device *dev = felix->ocelot.dev; 323*bdeced75SVladimir Oltean struct device_node *child; 324*bdeced75SVladimir Oltean 325*bdeced75SVladimir Oltean for_each_child_of_node(ports_node, child) { 326*bdeced75SVladimir Oltean phy_interface_t phy_mode; 327*bdeced75SVladimir Oltean u32 port; 328*bdeced75SVladimir Oltean int err; 329*bdeced75SVladimir Oltean 330*bdeced75SVladimir Oltean /* Get switch port number from DT */ 331*bdeced75SVladimir Oltean if (of_property_read_u32(child, "reg", &port) < 0) { 332*bdeced75SVladimir Oltean dev_err(dev, "Port number not defined in device tree " 333*bdeced75SVladimir Oltean "(property \"reg\")\n"); 334*bdeced75SVladimir Oltean of_node_put(child); 335*bdeced75SVladimir Oltean return -ENODEV; 336*bdeced75SVladimir Oltean } 337*bdeced75SVladimir Oltean 338*bdeced75SVladimir Oltean /* Get PHY mode from DT */ 339*bdeced75SVladimir Oltean err = of_get_phy_mode(child, &phy_mode); 340*bdeced75SVladimir Oltean if (err) { 341*bdeced75SVladimir Oltean dev_err(dev, "Failed to read phy-mode or " 342*bdeced75SVladimir Oltean "phy-interface-type property for port %d\n", 343*bdeced75SVladimir Oltean port); 344*bdeced75SVladimir Oltean of_node_put(child); 345*bdeced75SVladimir Oltean return -ENODEV; 346*bdeced75SVladimir Oltean } 347*bdeced75SVladimir Oltean 348*bdeced75SVladimir Oltean err = felix->info->prevalidate_phy_mode(ocelot, port, phy_mode); 349*bdeced75SVladimir Oltean if (err < 0) { 350*bdeced75SVladimir Oltean dev_err(dev, "Unsupported PHY mode %s on port %d\n", 351*bdeced75SVladimir Oltean phy_modes(phy_mode), port); 352*bdeced75SVladimir Oltean return err; 353*bdeced75SVladimir Oltean } 354*bdeced75SVladimir Oltean 355*bdeced75SVladimir Oltean port_phy_modes[port] = phy_mode; 356*bdeced75SVladimir Oltean } 357*bdeced75SVladimir Oltean 358*bdeced75SVladimir Oltean return 0; 359*bdeced75SVladimir Oltean } 360*bdeced75SVladimir Oltean 361*bdeced75SVladimir Oltean static int felix_parse_dt(struct felix *felix, phy_interface_t *port_phy_modes) 362*bdeced75SVladimir Oltean { 363*bdeced75SVladimir Oltean struct device *dev = felix->ocelot.dev; 364*bdeced75SVladimir Oltean struct device_node *switch_node; 365*bdeced75SVladimir Oltean struct device_node *ports_node; 366*bdeced75SVladimir Oltean int err; 367*bdeced75SVladimir Oltean 368*bdeced75SVladimir Oltean switch_node = dev->of_node; 369*bdeced75SVladimir Oltean 370*bdeced75SVladimir Oltean ports_node = of_get_child_by_name(switch_node, "ports"); 371*bdeced75SVladimir Oltean if (!ports_node) { 372*bdeced75SVladimir Oltean dev_err(dev, "Incorrect bindings: absent \"ports\" node\n"); 373*bdeced75SVladimir Oltean return -ENODEV; 374*bdeced75SVladimir Oltean } 375*bdeced75SVladimir Oltean 376*bdeced75SVladimir Oltean err = felix_parse_ports_node(felix, ports_node, port_phy_modes); 377*bdeced75SVladimir Oltean of_node_put(ports_node); 378*bdeced75SVladimir Oltean 379*bdeced75SVladimir Oltean return err; 380*bdeced75SVladimir Oltean } 381*bdeced75SVladimir Oltean 38256051948SVladimir Oltean static int felix_init_structs(struct felix *felix, int num_phys_ports) 38356051948SVladimir Oltean { 38456051948SVladimir Oltean struct ocelot *ocelot = &felix->ocelot; 385*bdeced75SVladimir Oltean phy_interface_t *port_phy_modes; 386*bdeced75SVladimir Oltean resource_size_t switch_base; 38756051948SVladimir Oltean int port, i, err; 38856051948SVladimir Oltean 38956051948SVladimir Oltean ocelot->num_phys_ports = num_phys_ports; 39056051948SVladimir Oltean ocelot->ports = devm_kcalloc(ocelot->dev, num_phys_ports, 39156051948SVladimir Oltean sizeof(struct ocelot_port *), GFP_KERNEL); 39256051948SVladimir Oltean if (!ocelot->ports) 39356051948SVladimir Oltean return -ENOMEM; 39456051948SVladimir Oltean 39556051948SVladimir Oltean ocelot->map = felix->info->map; 39656051948SVladimir Oltean ocelot->stats_layout = felix->info->stats_layout; 39756051948SVladimir Oltean ocelot->num_stats = felix->info->num_stats; 39856051948SVladimir Oltean ocelot->shared_queue_sz = felix->info->shared_queue_sz; 39956051948SVladimir Oltean ocelot->ops = felix->info->ops; 40056051948SVladimir Oltean 401*bdeced75SVladimir Oltean port_phy_modes = kcalloc(num_phys_ports, sizeof(phy_interface_t), 402*bdeced75SVladimir Oltean GFP_KERNEL); 403*bdeced75SVladimir Oltean if (!port_phy_modes) 404*bdeced75SVladimir Oltean return -ENOMEM; 405*bdeced75SVladimir Oltean 406*bdeced75SVladimir Oltean err = felix_parse_dt(felix, port_phy_modes); 407*bdeced75SVladimir Oltean if (err) { 408*bdeced75SVladimir Oltean kfree(port_phy_modes); 409*bdeced75SVladimir Oltean return err; 410*bdeced75SVladimir Oltean } 411*bdeced75SVladimir Oltean 412*bdeced75SVladimir Oltean switch_base = pci_resource_start(felix->pdev, 413*bdeced75SVladimir Oltean felix->info->switch_pci_bar); 41456051948SVladimir Oltean 41556051948SVladimir Oltean for (i = 0; i < TARGET_MAX; i++) { 41656051948SVladimir Oltean struct regmap *target; 41756051948SVladimir Oltean struct resource *res; 41856051948SVladimir Oltean 41956051948SVladimir Oltean if (!felix->info->target_io_res[i].name) 42056051948SVladimir Oltean continue; 42156051948SVladimir Oltean 42256051948SVladimir Oltean res = &felix->info->target_io_res[i]; 42356051948SVladimir Oltean res->flags = IORESOURCE_MEM; 424*bdeced75SVladimir Oltean res->start += switch_base; 425*bdeced75SVladimir Oltean res->end += switch_base; 42656051948SVladimir Oltean 42756051948SVladimir Oltean target = ocelot_regmap_init(ocelot, res); 42856051948SVladimir Oltean if (IS_ERR(target)) { 42956051948SVladimir Oltean dev_err(ocelot->dev, 43056051948SVladimir Oltean "Failed to map device memory space\n"); 431*bdeced75SVladimir Oltean kfree(port_phy_modes); 43256051948SVladimir Oltean return PTR_ERR(target); 43356051948SVladimir Oltean } 43456051948SVladimir Oltean 43556051948SVladimir Oltean ocelot->targets[i] = target; 43656051948SVladimir Oltean } 43756051948SVladimir Oltean 43856051948SVladimir Oltean err = ocelot_regfields_init(ocelot, felix->info->regfields); 43956051948SVladimir Oltean if (err) { 44056051948SVladimir Oltean dev_err(ocelot->dev, "failed to init reg fields map\n"); 441*bdeced75SVladimir Oltean kfree(port_phy_modes); 44256051948SVladimir Oltean return err; 44356051948SVladimir Oltean } 44456051948SVladimir Oltean 44556051948SVladimir Oltean for (port = 0; port < num_phys_ports; port++) { 44656051948SVladimir Oltean struct ocelot_port *ocelot_port; 44756051948SVladimir Oltean void __iomem *port_regs; 44856051948SVladimir Oltean struct resource *res; 44956051948SVladimir Oltean 45056051948SVladimir Oltean ocelot_port = devm_kzalloc(ocelot->dev, 45156051948SVladimir Oltean sizeof(struct ocelot_port), 45256051948SVladimir Oltean GFP_KERNEL); 45356051948SVladimir Oltean if (!ocelot_port) { 45456051948SVladimir Oltean dev_err(ocelot->dev, 45556051948SVladimir Oltean "failed to allocate port memory\n"); 456*bdeced75SVladimir Oltean kfree(port_phy_modes); 45756051948SVladimir Oltean return -ENOMEM; 45856051948SVladimir Oltean } 45956051948SVladimir Oltean 46056051948SVladimir Oltean res = &felix->info->port_io_res[port]; 46156051948SVladimir Oltean res->flags = IORESOURCE_MEM; 462*bdeced75SVladimir Oltean res->start += switch_base; 463*bdeced75SVladimir Oltean res->end += switch_base; 46456051948SVladimir Oltean 46556051948SVladimir Oltean port_regs = devm_ioremap_resource(ocelot->dev, res); 46656051948SVladimir Oltean if (IS_ERR(port_regs)) { 46756051948SVladimir Oltean dev_err(ocelot->dev, 46856051948SVladimir Oltean "failed to map registers for port %d\n", port); 469*bdeced75SVladimir Oltean kfree(port_phy_modes); 47056051948SVladimir Oltean return PTR_ERR(port_regs); 47156051948SVladimir Oltean } 47256051948SVladimir Oltean 473*bdeced75SVladimir Oltean ocelot_port->phy_mode = port_phy_modes[port]; 47456051948SVladimir Oltean ocelot_port->ocelot = ocelot; 47556051948SVladimir Oltean ocelot_port->regs = port_regs; 47656051948SVladimir Oltean ocelot->ports[port] = ocelot_port; 47756051948SVladimir Oltean } 47856051948SVladimir Oltean 479*bdeced75SVladimir Oltean kfree(port_phy_modes); 480*bdeced75SVladimir Oltean 481*bdeced75SVladimir Oltean if (felix->info->mdio_bus_alloc) { 482*bdeced75SVladimir Oltean err = felix->info->mdio_bus_alloc(ocelot); 483*bdeced75SVladimir Oltean if (err < 0) 484*bdeced75SVladimir Oltean return err; 485*bdeced75SVladimir Oltean } 486*bdeced75SVladimir Oltean 48756051948SVladimir Oltean return 0; 48856051948SVladimir Oltean } 48956051948SVladimir Oltean 49056051948SVladimir Oltean /* Hardware initialization done here so that we can allocate structures with 49156051948SVladimir Oltean * devm without fear of dsa_register_switch returning -EPROBE_DEFER and causing 49256051948SVladimir Oltean * us to allocate structures twice (leak memory) and map PCI memory twice 49356051948SVladimir Oltean * (which will not work). 49456051948SVladimir Oltean */ 49556051948SVladimir Oltean static int felix_setup(struct dsa_switch *ds) 49656051948SVladimir Oltean { 49756051948SVladimir Oltean struct ocelot *ocelot = ds->priv; 49856051948SVladimir Oltean struct felix *felix = ocelot_to_felix(ocelot); 49956051948SVladimir Oltean int port, err; 50056051948SVladimir Oltean 50156051948SVladimir Oltean err = felix_init_structs(felix, ds->num_ports); 50256051948SVladimir Oltean if (err) 50356051948SVladimir Oltean return err; 50456051948SVladimir Oltean 50556051948SVladimir Oltean ocelot_init(ocelot); 50656051948SVladimir Oltean 50756051948SVladimir Oltean for (port = 0; port < ds->num_ports; port++) { 50856051948SVladimir Oltean ocelot_init_port(ocelot, port); 50956051948SVladimir Oltean 510b8fc7177SVladimir Oltean if (dsa_is_cpu_port(ds, port)) 51156051948SVladimir Oltean ocelot_set_cpu_port(ocelot, port, 51256051948SVladimir Oltean OCELOT_TAG_PREFIX_NONE, 51356051948SVladimir Oltean OCELOT_TAG_PREFIX_LONG); 51456051948SVladimir Oltean } 51556051948SVladimir Oltean 516*bdeced75SVladimir Oltean /* It looks like the MAC/PCS interrupt register - PM0_IEVENT (0x8040) 517*bdeced75SVladimir Oltean * isn't instantiated for the Felix PF. 518*bdeced75SVladimir Oltean * In-band AN may take a few ms to complete, so we need to poll. 519*bdeced75SVladimir Oltean */ 520*bdeced75SVladimir Oltean ds->pcs_poll = true; 521*bdeced75SVladimir Oltean 52256051948SVladimir Oltean return 0; 52356051948SVladimir Oltean } 52456051948SVladimir Oltean 52556051948SVladimir Oltean static void felix_teardown(struct dsa_switch *ds) 52656051948SVladimir Oltean { 52756051948SVladimir Oltean struct ocelot *ocelot = ds->priv; 528*bdeced75SVladimir Oltean struct felix *felix = ocelot_to_felix(ocelot); 529*bdeced75SVladimir Oltean 530*bdeced75SVladimir Oltean if (felix->info->mdio_bus_free) 531*bdeced75SVladimir Oltean felix->info->mdio_bus_free(ocelot); 53256051948SVladimir Oltean 53356051948SVladimir Oltean /* stop workqueue thread */ 53456051948SVladimir Oltean ocelot_deinit(ocelot); 53556051948SVladimir Oltean } 53656051948SVladimir Oltean 537c0bcf537SYangbo Lu static int felix_hwtstamp_get(struct dsa_switch *ds, int port, 538c0bcf537SYangbo Lu struct ifreq *ifr) 539c0bcf537SYangbo Lu { 540c0bcf537SYangbo Lu struct ocelot *ocelot = ds->priv; 541c0bcf537SYangbo Lu 542c0bcf537SYangbo Lu return ocelot_hwstamp_get(ocelot, port, ifr); 543c0bcf537SYangbo Lu } 544c0bcf537SYangbo Lu 545c0bcf537SYangbo Lu static int felix_hwtstamp_set(struct dsa_switch *ds, int port, 546c0bcf537SYangbo Lu struct ifreq *ifr) 547c0bcf537SYangbo Lu { 548c0bcf537SYangbo Lu struct ocelot *ocelot = ds->priv; 549c0bcf537SYangbo Lu 550c0bcf537SYangbo Lu return ocelot_hwstamp_set(ocelot, port, ifr); 551c0bcf537SYangbo Lu } 552c0bcf537SYangbo Lu 553c0bcf537SYangbo Lu static bool felix_rxtstamp(struct dsa_switch *ds, int port, 554c0bcf537SYangbo Lu struct sk_buff *skb, unsigned int type) 555c0bcf537SYangbo Lu { 556c0bcf537SYangbo Lu struct skb_shared_hwtstamps *shhwtstamps; 557c0bcf537SYangbo Lu struct ocelot *ocelot = ds->priv; 558c0bcf537SYangbo Lu u8 *extraction = skb->data - ETH_HLEN - OCELOT_TAG_LEN; 559c0bcf537SYangbo Lu u32 tstamp_lo, tstamp_hi; 560c0bcf537SYangbo Lu struct timespec64 ts; 561c0bcf537SYangbo Lu u64 tstamp, val; 562c0bcf537SYangbo Lu 563c0bcf537SYangbo Lu ocelot_ptp_gettime64(&ocelot->ptp_info, &ts); 564c0bcf537SYangbo Lu tstamp = ktime_set(ts.tv_sec, ts.tv_nsec); 565c0bcf537SYangbo Lu 566c0bcf537SYangbo Lu packing(extraction, &val, 116, 85, OCELOT_TAG_LEN, UNPACK, 0); 567c0bcf537SYangbo Lu tstamp_lo = (u32)val; 568c0bcf537SYangbo Lu 569c0bcf537SYangbo Lu tstamp_hi = tstamp >> 32; 570c0bcf537SYangbo Lu if ((tstamp & 0xffffffff) < tstamp_lo) 571c0bcf537SYangbo Lu tstamp_hi--; 572c0bcf537SYangbo Lu 573c0bcf537SYangbo Lu tstamp = ((u64)tstamp_hi << 32) | tstamp_lo; 574c0bcf537SYangbo Lu 575c0bcf537SYangbo Lu shhwtstamps = skb_hwtstamps(skb); 576c0bcf537SYangbo Lu memset(shhwtstamps, 0, sizeof(struct skb_shared_hwtstamps)); 577c0bcf537SYangbo Lu shhwtstamps->hwtstamp = tstamp; 578c0bcf537SYangbo Lu return false; 579c0bcf537SYangbo Lu } 580c0bcf537SYangbo Lu 5813243e04aSChen Wandun static bool felix_txtstamp(struct dsa_switch *ds, int port, 582c0bcf537SYangbo Lu struct sk_buff *clone, unsigned int type) 583c0bcf537SYangbo Lu { 584c0bcf537SYangbo Lu struct ocelot *ocelot = ds->priv; 585c0bcf537SYangbo Lu struct ocelot_port *ocelot_port = ocelot->ports[port]; 586c0bcf537SYangbo Lu 587c0bcf537SYangbo Lu if (!ocelot_port_add_txtstamp_skb(ocelot_port, clone)) 588c0bcf537SYangbo Lu return true; 589c0bcf537SYangbo Lu 590c0bcf537SYangbo Lu return false; 591c0bcf537SYangbo Lu } 592c0bcf537SYangbo Lu 59356051948SVladimir Oltean static const struct dsa_switch_ops felix_switch_ops = { 59456051948SVladimir Oltean .get_tag_protocol = felix_get_tag_protocol, 59556051948SVladimir Oltean .setup = felix_setup, 59656051948SVladimir Oltean .teardown = felix_teardown, 59756051948SVladimir Oltean .set_ageing_time = felix_set_ageing_time, 59856051948SVladimir Oltean .get_strings = felix_get_strings, 59956051948SVladimir Oltean .get_ethtool_stats = felix_get_ethtool_stats, 60056051948SVladimir Oltean .get_sset_count = felix_get_sset_count, 60156051948SVladimir Oltean .get_ts_info = felix_get_ts_info, 602*bdeced75SVladimir Oltean .phylink_validate = felix_phylink_validate, 603*bdeced75SVladimir Oltean .phylink_mac_link_state = felix_phylink_mac_pcs_get_state, 604*bdeced75SVladimir Oltean .phylink_mac_config = felix_phylink_mac_config, 605*bdeced75SVladimir Oltean .phylink_mac_an_restart = felix_phylink_mac_an_restart, 606*bdeced75SVladimir Oltean .phylink_mac_link_down = felix_phylink_mac_link_down, 607*bdeced75SVladimir Oltean .phylink_mac_link_up = felix_phylink_mac_link_up, 60856051948SVladimir Oltean .port_enable = felix_port_enable, 60956051948SVladimir Oltean .port_disable = felix_port_disable, 61056051948SVladimir Oltean .port_fdb_dump = felix_fdb_dump, 61156051948SVladimir Oltean .port_fdb_add = felix_fdb_add, 61256051948SVladimir Oltean .port_fdb_del = felix_fdb_del, 61356051948SVladimir Oltean .port_bridge_join = felix_bridge_join, 61456051948SVladimir Oltean .port_bridge_leave = felix_bridge_leave, 61556051948SVladimir Oltean .port_stp_state_set = felix_bridge_stp_state_set, 61656051948SVladimir Oltean .port_vlan_prepare = felix_vlan_prepare, 61756051948SVladimir Oltean .port_vlan_filtering = felix_vlan_filtering, 61856051948SVladimir Oltean .port_vlan_add = felix_vlan_add, 61956051948SVladimir Oltean .port_vlan_del = felix_vlan_del, 620c0bcf537SYangbo Lu .port_hwtstamp_get = felix_hwtstamp_get, 621c0bcf537SYangbo Lu .port_hwtstamp_set = felix_hwtstamp_set, 622c0bcf537SYangbo Lu .port_rxtstamp = felix_rxtstamp, 623c0bcf537SYangbo Lu .port_txtstamp = felix_txtstamp, 62456051948SVladimir Oltean }; 62556051948SVladimir Oltean 62656051948SVladimir Oltean static struct felix_info *felix_instance_tbl[] = { 62756051948SVladimir Oltean [FELIX_INSTANCE_VSC9959] = &felix_info_vsc9959, 62856051948SVladimir Oltean }; 62956051948SVladimir Oltean 630c0bcf537SYangbo Lu static irqreturn_t felix_irq_handler(int irq, void *data) 631c0bcf537SYangbo Lu { 632c0bcf537SYangbo Lu struct ocelot *ocelot = (struct ocelot *)data; 633c0bcf537SYangbo Lu 634c0bcf537SYangbo Lu /* The INTB interrupt is used for both PTP TX timestamp interrupt 635c0bcf537SYangbo Lu * and preemption status change interrupt on each port. 636c0bcf537SYangbo Lu * 637c0bcf537SYangbo Lu * - Get txtstamp if have 638c0bcf537SYangbo Lu * - TODO: handle preemption. Without handling it, driver may get 639c0bcf537SYangbo Lu * interrupt storm. 640c0bcf537SYangbo Lu */ 641c0bcf537SYangbo Lu 642c0bcf537SYangbo Lu ocelot_get_txtstamp(ocelot); 643c0bcf537SYangbo Lu 644c0bcf537SYangbo Lu return IRQ_HANDLED; 645c0bcf537SYangbo Lu } 646c0bcf537SYangbo Lu 64756051948SVladimir Oltean static int felix_pci_probe(struct pci_dev *pdev, 64856051948SVladimir Oltean const struct pci_device_id *id) 64956051948SVladimir Oltean { 65056051948SVladimir Oltean enum felix_instance instance = id->driver_data; 65156051948SVladimir Oltean struct dsa_switch *ds; 65256051948SVladimir Oltean struct ocelot *ocelot; 65356051948SVladimir Oltean struct felix *felix; 65456051948SVladimir Oltean int err; 65556051948SVladimir Oltean 65656051948SVladimir Oltean err = pci_enable_device(pdev); 65756051948SVladimir Oltean if (err) { 65856051948SVladimir Oltean dev_err(&pdev->dev, "device enable failed\n"); 65956051948SVladimir Oltean goto err_pci_enable; 66056051948SVladimir Oltean } 66156051948SVladimir Oltean 66256051948SVladimir Oltean /* set up for high or low dma */ 66356051948SVladimir Oltean err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64)); 66456051948SVladimir Oltean if (err) { 66556051948SVladimir Oltean err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32)); 66656051948SVladimir Oltean if (err) { 66756051948SVladimir Oltean dev_err(&pdev->dev, 66856051948SVladimir Oltean "DMA configuration failed: 0x%x\n", err); 66956051948SVladimir Oltean goto err_dma; 67056051948SVladimir Oltean } 67156051948SVladimir Oltean } 67256051948SVladimir Oltean 67356051948SVladimir Oltean felix = kzalloc(sizeof(struct felix), GFP_KERNEL); 67456051948SVladimir Oltean if (!felix) { 67556051948SVladimir Oltean err = -ENOMEM; 67656051948SVladimir Oltean dev_err(&pdev->dev, "Failed to allocate driver memory\n"); 67756051948SVladimir Oltean goto err_alloc_felix; 67856051948SVladimir Oltean } 67956051948SVladimir Oltean 68056051948SVladimir Oltean pci_set_drvdata(pdev, felix); 68156051948SVladimir Oltean ocelot = &felix->ocelot; 68256051948SVladimir Oltean ocelot->dev = &pdev->dev; 68356051948SVladimir Oltean felix->pdev = pdev; 68456051948SVladimir Oltean felix->info = felix_instance_tbl[instance]; 68556051948SVladimir Oltean 68656051948SVladimir Oltean pci_set_master(pdev); 68756051948SVladimir Oltean 688c0bcf537SYangbo Lu err = devm_request_threaded_irq(&pdev->dev, pdev->irq, NULL, 689c0bcf537SYangbo Lu &felix_irq_handler, IRQF_ONESHOT, 690c0bcf537SYangbo Lu "felix-intb", ocelot); 691c0bcf537SYangbo Lu if (err) { 692c0bcf537SYangbo Lu dev_err(&pdev->dev, "Failed to request irq\n"); 693c0bcf537SYangbo Lu goto err_alloc_irq; 694c0bcf537SYangbo Lu } 695c0bcf537SYangbo Lu 696c0bcf537SYangbo Lu ocelot->ptp = 1; 697c0bcf537SYangbo Lu 69856051948SVladimir Oltean ds = kzalloc(sizeof(struct dsa_switch), GFP_KERNEL); 69956051948SVladimir Oltean if (!ds) { 70056051948SVladimir Oltean err = -ENOMEM; 70156051948SVladimir Oltean dev_err(&pdev->dev, "Failed to allocate DSA switch\n"); 70256051948SVladimir Oltean goto err_alloc_ds; 70356051948SVladimir Oltean } 70456051948SVladimir Oltean 70556051948SVladimir Oltean ds->dev = &pdev->dev; 70656051948SVladimir Oltean ds->num_ports = felix->info->num_ports; 70756051948SVladimir Oltean ds->ops = &felix_switch_ops; 70856051948SVladimir Oltean ds->priv = ocelot; 70956051948SVladimir Oltean felix->ds = ds; 71056051948SVladimir Oltean 71156051948SVladimir Oltean err = dsa_register_switch(ds); 71256051948SVladimir Oltean if (err) { 71356051948SVladimir Oltean dev_err(&pdev->dev, "Failed to register DSA switch: %d\n", err); 71456051948SVladimir Oltean goto err_register_ds; 71556051948SVladimir Oltean } 71656051948SVladimir Oltean 71756051948SVladimir Oltean return 0; 71856051948SVladimir Oltean 71956051948SVladimir Oltean err_register_ds: 72056051948SVladimir Oltean kfree(ds); 72156051948SVladimir Oltean err_alloc_ds: 722c0bcf537SYangbo Lu err_alloc_irq: 72356051948SVladimir Oltean err_alloc_felix: 72456051948SVladimir Oltean kfree(felix); 72556051948SVladimir Oltean err_dma: 72656051948SVladimir Oltean pci_disable_device(pdev); 72756051948SVladimir Oltean err_pci_enable: 72856051948SVladimir Oltean return err; 72956051948SVladimir Oltean } 73056051948SVladimir Oltean 73156051948SVladimir Oltean static void felix_pci_remove(struct pci_dev *pdev) 73256051948SVladimir Oltean { 73356051948SVladimir Oltean struct felix *felix; 73456051948SVladimir Oltean 73556051948SVladimir Oltean felix = pci_get_drvdata(pdev); 73656051948SVladimir Oltean 73756051948SVladimir Oltean dsa_unregister_switch(felix->ds); 73856051948SVladimir Oltean 73956051948SVladimir Oltean kfree(felix->ds); 74056051948SVladimir Oltean kfree(felix); 74156051948SVladimir Oltean 74256051948SVladimir Oltean pci_disable_device(pdev); 74356051948SVladimir Oltean } 74456051948SVladimir Oltean 74556051948SVladimir Oltean static struct pci_device_id felix_ids[] = { 74656051948SVladimir Oltean { 74756051948SVladimir Oltean /* NXP LS1028A */ 74856051948SVladimir Oltean PCI_DEVICE(PCI_VENDOR_ID_FREESCALE, 0xEEF0), 74956051948SVladimir Oltean .driver_data = FELIX_INSTANCE_VSC9959, 75056051948SVladimir Oltean }, 75156051948SVladimir Oltean { 0, } 75256051948SVladimir Oltean }; 75356051948SVladimir Oltean MODULE_DEVICE_TABLE(pci, felix_ids); 75456051948SVladimir Oltean 75556051948SVladimir Oltean static struct pci_driver felix_pci_driver = { 75656051948SVladimir Oltean .name = KBUILD_MODNAME, 75756051948SVladimir Oltean .id_table = felix_ids, 75856051948SVladimir Oltean .probe = felix_pci_probe, 75956051948SVladimir Oltean .remove = felix_pci_remove, 76056051948SVladimir Oltean }; 76156051948SVladimir Oltean 76256051948SVladimir Oltean module_pci_driver(felix_pci_driver); 76356051948SVladimir Oltean 76456051948SVladimir Oltean MODULE_DESCRIPTION("Felix Switch driver"); 76556051948SVladimir Oltean MODULE_LICENSE("GPL v2"); 766