156051948SVladimir Oltean // SPDX-License-Identifier: GPL-2.0 256051948SVladimir Oltean /* Copyright 2019 NXP Semiconductors 356051948SVladimir Oltean */ 456051948SVladimir Oltean #include <uapi/linux/if_bridge.h> 556051948SVladimir Oltean #include <soc/mscc/ocelot.h> 656051948SVladimir Oltean #include <linux/module.h> 756051948SVladimir Oltean #include <linux/pci.h> 856051948SVladimir Oltean #include <linux/of.h> 956051948SVladimir Oltean #include <net/dsa.h> 1056051948SVladimir Oltean #include "felix.h" 1156051948SVladimir Oltean 1256051948SVladimir Oltean static enum dsa_tag_protocol felix_get_tag_protocol(struct dsa_switch *ds, 1356051948SVladimir Oltean int port) 1456051948SVladimir Oltean { 1556051948SVladimir Oltean return DSA_TAG_PROTO_OCELOT; 1656051948SVladimir Oltean } 1756051948SVladimir Oltean 1856051948SVladimir Oltean static int felix_set_ageing_time(struct dsa_switch *ds, 1956051948SVladimir Oltean unsigned int ageing_time) 2056051948SVladimir Oltean { 2156051948SVladimir Oltean struct ocelot *ocelot = ds->priv; 2256051948SVladimir Oltean 2356051948SVladimir Oltean ocelot_set_ageing_time(ocelot, ageing_time); 2456051948SVladimir Oltean 2556051948SVladimir Oltean return 0; 2656051948SVladimir Oltean } 2756051948SVladimir Oltean 2856051948SVladimir Oltean static void felix_adjust_link(struct dsa_switch *ds, int port, 2956051948SVladimir Oltean struct phy_device *phydev) 3056051948SVladimir Oltean { 3156051948SVladimir Oltean struct ocelot *ocelot = ds->priv; 3256051948SVladimir Oltean 3356051948SVladimir Oltean ocelot_adjust_link(ocelot, port, phydev); 3456051948SVladimir Oltean } 3556051948SVladimir Oltean 3656051948SVladimir Oltean static int felix_fdb_dump(struct dsa_switch *ds, int port, 3756051948SVladimir Oltean dsa_fdb_dump_cb_t *cb, void *data) 3856051948SVladimir Oltean { 3956051948SVladimir Oltean struct ocelot *ocelot = ds->priv; 4056051948SVladimir Oltean 4156051948SVladimir Oltean return ocelot_fdb_dump(ocelot, port, cb, data); 4256051948SVladimir Oltean } 4356051948SVladimir Oltean 4456051948SVladimir Oltean static int felix_fdb_add(struct dsa_switch *ds, int port, 4556051948SVladimir Oltean const unsigned char *addr, u16 vid) 4656051948SVladimir Oltean { 4756051948SVladimir Oltean struct ocelot *ocelot = ds->priv; 4856051948SVladimir Oltean bool vlan_aware; 4956051948SVladimir Oltean 5056051948SVladimir Oltean vlan_aware = dsa_port_is_vlan_filtering(dsa_to_port(ds, port)); 5156051948SVladimir Oltean 5256051948SVladimir Oltean return ocelot_fdb_add(ocelot, port, addr, vid, vlan_aware); 5356051948SVladimir Oltean } 5456051948SVladimir Oltean 5556051948SVladimir Oltean static int felix_fdb_del(struct dsa_switch *ds, int port, 5656051948SVladimir Oltean const unsigned char *addr, u16 vid) 5756051948SVladimir Oltean { 5856051948SVladimir Oltean struct ocelot *ocelot = ds->priv; 5956051948SVladimir Oltean 6056051948SVladimir Oltean return ocelot_fdb_del(ocelot, port, addr, vid); 6156051948SVladimir Oltean } 6256051948SVladimir Oltean 6356051948SVladimir Oltean static void felix_bridge_stp_state_set(struct dsa_switch *ds, int port, 6456051948SVladimir Oltean u8 state) 6556051948SVladimir Oltean { 6656051948SVladimir Oltean struct ocelot *ocelot = ds->priv; 6756051948SVladimir Oltean 6856051948SVladimir Oltean return ocelot_bridge_stp_state_set(ocelot, port, state); 6956051948SVladimir Oltean } 7056051948SVladimir Oltean 7156051948SVladimir Oltean static int felix_bridge_join(struct dsa_switch *ds, int port, 7256051948SVladimir Oltean struct net_device *br) 7356051948SVladimir Oltean { 7456051948SVladimir Oltean struct ocelot *ocelot = ds->priv; 7556051948SVladimir Oltean 7656051948SVladimir Oltean return ocelot_port_bridge_join(ocelot, port, br); 7756051948SVladimir Oltean } 7856051948SVladimir Oltean 7956051948SVladimir Oltean static void felix_bridge_leave(struct dsa_switch *ds, int port, 8056051948SVladimir Oltean struct net_device *br) 8156051948SVladimir Oltean { 8256051948SVladimir Oltean struct ocelot *ocelot = ds->priv; 8356051948SVladimir Oltean 8456051948SVladimir Oltean ocelot_port_bridge_leave(ocelot, port, br); 8556051948SVladimir Oltean } 8656051948SVladimir Oltean 8756051948SVladimir Oltean /* This callback needs to be present */ 8856051948SVladimir Oltean static int felix_vlan_prepare(struct dsa_switch *ds, int port, 8956051948SVladimir Oltean const struct switchdev_obj_port_vlan *vlan) 9056051948SVladimir Oltean { 9156051948SVladimir Oltean return 0; 9256051948SVladimir Oltean } 9356051948SVladimir Oltean 9456051948SVladimir Oltean static int felix_vlan_filtering(struct dsa_switch *ds, int port, bool enabled) 9556051948SVladimir Oltean { 9656051948SVladimir Oltean struct ocelot *ocelot = ds->priv; 9756051948SVladimir Oltean 9856051948SVladimir Oltean ocelot_port_vlan_filtering(ocelot, port, enabled); 9956051948SVladimir Oltean 10056051948SVladimir Oltean return 0; 10156051948SVladimir Oltean } 10256051948SVladimir Oltean 10356051948SVladimir Oltean static void felix_vlan_add(struct dsa_switch *ds, int port, 10456051948SVladimir Oltean const struct switchdev_obj_port_vlan *vlan) 10556051948SVladimir Oltean { 10656051948SVladimir Oltean struct ocelot *ocelot = ds->priv; 10756051948SVladimir Oltean u16 vid; 10856051948SVladimir Oltean int err; 10956051948SVladimir Oltean 11056051948SVladimir Oltean for (vid = vlan->vid_begin; vid <= vlan->vid_end; vid++) { 11156051948SVladimir Oltean err = ocelot_vlan_add(ocelot, port, vid, 11256051948SVladimir Oltean vlan->flags & BRIDGE_VLAN_INFO_PVID, 11356051948SVladimir Oltean vlan->flags & BRIDGE_VLAN_INFO_UNTAGGED); 11456051948SVladimir Oltean if (err) { 11556051948SVladimir Oltean dev_err(ds->dev, "Failed to add VLAN %d to port %d: %d\n", 11656051948SVladimir Oltean vid, port, err); 11756051948SVladimir Oltean return; 11856051948SVladimir Oltean } 11956051948SVladimir Oltean } 12056051948SVladimir Oltean } 12156051948SVladimir Oltean 12256051948SVladimir Oltean static int felix_vlan_del(struct dsa_switch *ds, int port, 12356051948SVladimir Oltean const struct switchdev_obj_port_vlan *vlan) 12456051948SVladimir Oltean { 12556051948SVladimir Oltean struct ocelot *ocelot = ds->priv; 12656051948SVladimir Oltean u16 vid; 12756051948SVladimir Oltean int err; 12856051948SVladimir Oltean 12956051948SVladimir Oltean for (vid = vlan->vid_begin; vid <= vlan->vid_end; vid++) { 13056051948SVladimir Oltean err = ocelot_vlan_del(ocelot, port, vid); 13156051948SVladimir Oltean if (err) { 13256051948SVladimir Oltean dev_err(ds->dev, "Failed to remove VLAN %d from port %d: %d\n", 13356051948SVladimir Oltean vid, port, err); 13456051948SVladimir Oltean return err; 13556051948SVladimir Oltean } 13656051948SVladimir Oltean } 13756051948SVladimir Oltean return 0; 13856051948SVladimir Oltean } 13956051948SVladimir Oltean 14056051948SVladimir Oltean static int felix_port_enable(struct dsa_switch *ds, int port, 14156051948SVladimir Oltean struct phy_device *phy) 14256051948SVladimir Oltean { 14356051948SVladimir Oltean struct ocelot *ocelot = ds->priv; 14456051948SVladimir Oltean 14556051948SVladimir Oltean ocelot_port_enable(ocelot, port, phy); 14656051948SVladimir Oltean 14756051948SVladimir Oltean return 0; 14856051948SVladimir Oltean } 14956051948SVladimir Oltean 15056051948SVladimir Oltean static void felix_port_disable(struct dsa_switch *ds, int port) 15156051948SVladimir Oltean { 15256051948SVladimir Oltean struct ocelot *ocelot = ds->priv; 15356051948SVladimir Oltean 15456051948SVladimir Oltean return ocelot_port_disable(ocelot, port); 15556051948SVladimir Oltean } 15656051948SVladimir Oltean 15756051948SVladimir Oltean static void felix_get_strings(struct dsa_switch *ds, int port, 15856051948SVladimir Oltean u32 stringset, u8 *data) 15956051948SVladimir Oltean { 16056051948SVladimir Oltean struct ocelot *ocelot = ds->priv; 16156051948SVladimir Oltean 16256051948SVladimir Oltean return ocelot_get_strings(ocelot, port, stringset, data); 16356051948SVladimir Oltean } 16456051948SVladimir Oltean 16556051948SVladimir Oltean static void felix_get_ethtool_stats(struct dsa_switch *ds, int port, u64 *data) 16656051948SVladimir Oltean { 16756051948SVladimir Oltean struct ocelot *ocelot = ds->priv; 16856051948SVladimir Oltean 16956051948SVladimir Oltean ocelot_get_ethtool_stats(ocelot, port, data); 17056051948SVladimir Oltean } 17156051948SVladimir Oltean 17256051948SVladimir Oltean static int felix_get_sset_count(struct dsa_switch *ds, int port, int sset) 17356051948SVladimir Oltean { 17456051948SVladimir Oltean struct ocelot *ocelot = ds->priv; 17556051948SVladimir Oltean 17656051948SVladimir Oltean return ocelot_get_sset_count(ocelot, port, sset); 17756051948SVladimir Oltean } 17856051948SVladimir Oltean 17956051948SVladimir Oltean static int felix_get_ts_info(struct dsa_switch *ds, int port, 18056051948SVladimir Oltean struct ethtool_ts_info *info) 18156051948SVladimir Oltean { 18256051948SVladimir Oltean struct ocelot *ocelot = ds->priv; 18356051948SVladimir Oltean 18456051948SVladimir Oltean return ocelot_get_ts_info(ocelot, port, info); 18556051948SVladimir Oltean } 18656051948SVladimir Oltean 18756051948SVladimir Oltean static int felix_init_structs(struct felix *felix, int num_phys_ports) 18856051948SVladimir Oltean { 18956051948SVladimir Oltean struct ocelot *ocelot = &felix->ocelot; 19056051948SVladimir Oltean resource_size_t base; 19156051948SVladimir Oltean int port, i, err; 19256051948SVladimir Oltean 19356051948SVladimir Oltean ocelot->num_phys_ports = num_phys_ports; 19456051948SVladimir Oltean ocelot->ports = devm_kcalloc(ocelot->dev, num_phys_ports, 19556051948SVladimir Oltean sizeof(struct ocelot_port *), GFP_KERNEL); 19656051948SVladimir Oltean if (!ocelot->ports) 19756051948SVladimir Oltean return -ENOMEM; 19856051948SVladimir Oltean 19956051948SVladimir Oltean ocelot->map = felix->info->map; 20056051948SVladimir Oltean ocelot->stats_layout = felix->info->stats_layout; 20156051948SVladimir Oltean ocelot->num_stats = felix->info->num_stats; 20256051948SVladimir Oltean ocelot->shared_queue_sz = felix->info->shared_queue_sz; 20356051948SVladimir Oltean ocelot->ops = felix->info->ops; 20456051948SVladimir Oltean 20556051948SVladimir Oltean base = pci_resource_start(felix->pdev, felix->info->pci_bar); 20656051948SVladimir Oltean 20756051948SVladimir Oltean for (i = 0; i < TARGET_MAX; i++) { 20856051948SVladimir Oltean struct regmap *target; 20956051948SVladimir Oltean struct resource *res; 21056051948SVladimir Oltean 21156051948SVladimir Oltean if (!felix->info->target_io_res[i].name) 21256051948SVladimir Oltean continue; 21356051948SVladimir Oltean 21456051948SVladimir Oltean res = &felix->info->target_io_res[i]; 21556051948SVladimir Oltean res->flags = IORESOURCE_MEM; 21656051948SVladimir Oltean res->start += base; 21756051948SVladimir Oltean res->end += base; 21856051948SVladimir Oltean 21956051948SVladimir Oltean target = ocelot_regmap_init(ocelot, res); 22056051948SVladimir Oltean if (IS_ERR(target)) { 22156051948SVladimir Oltean dev_err(ocelot->dev, 22256051948SVladimir Oltean "Failed to map device memory space\n"); 22356051948SVladimir Oltean return PTR_ERR(target); 22456051948SVladimir Oltean } 22556051948SVladimir Oltean 22656051948SVladimir Oltean ocelot->targets[i] = target; 22756051948SVladimir Oltean } 22856051948SVladimir Oltean 22956051948SVladimir Oltean err = ocelot_regfields_init(ocelot, felix->info->regfields); 23056051948SVladimir Oltean if (err) { 23156051948SVladimir Oltean dev_err(ocelot->dev, "failed to init reg fields map\n"); 23256051948SVladimir Oltean return err; 23356051948SVladimir Oltean } 23456051948SVladimir Oltean 23556051948SVladimir Oltean for (port = 0; port < num_phys_ports; port++) { 23656051948SVladimir Oltean struct ocelot_port *ocelot_port; 23756051948SVladimir Oltean void __iomem *port_regs; 23856051948SVladimir Oltean struct resource *res; 23956051948SVladimir Oltean 24056051948SVladimir Oltean ocelot_port = devm_kzalloc(ocelot->dev, 24156051948SVladimir Oltean sizeof(struct ocelot_port), 24256051948SVladimir Oltean GFP_KERNEL); 24356051948SVladimir Oltean if (!ocelot_port) { 24456051948SVladimir Oltean dev_err(ocelot->dev, 24556051948SVladimir Oltean "failed to allocate port memory\n"); 24656051948SVladimir Oltean return -ENOMEM; 24756051948SVladimir Oltean } 24856051948SVladimir Oltean 24956051948SVladimir Oltean res = &felix->info->port_io_res[port]; 25056051948SVladimir Oltean res->flags = IORESOURCE_MEM; 25156051948SVladimir Oltean res->start += base; 25256051948SVladimir Oltean res->end += base; 25356051948SVladimir Oltean 25456051948SVladimir Oltean port_regs = devm_ioremap_resource(ocelot->dev, res); 25556051948SVladimir Oltean if (IS_ERR(port_regs)) { 25656051948SVladimir Oltean dev_err(ocelot->dev, 25756051948SVladimir Oltean "failed to map registers for port %d\n", port); 25856051948SVladimir Oltean return PTR_ERR(port_regs); 25956051948SVladimir Oltean } 26056051948SVladimir Oltean 26156051948SVladimir Oltean ocelot_port->ocelot = ocelot; 26256051948SVladimir Oltean ocelot_port->regs = port_regs; 26356051948SVladimir Oltean ocelot->ports[port] = ocelot_port; 26456051948SVladimir Oltean } 26556051948SVladimir Oltean 26656051948SVladimir Oltean return 0; 26756051948SVladimir Oltean } 26856051948SVladimir Oltean 26956051948SVladimir Oltean /* Hardware initialization done here so that we can allocate structures with 27056051948SVladimir Oltean * devm without fear of dsa_register_switch returning -EPROBE_DEFER and causing 27156051948SVladimir Oltean * us to allocate structures twice (leak memory) and map PCI memory twice 27256051948SVladimir Oltean * (which will not work). 27356051948SVladimir Oltean */ 27456051948SVladimir Oltean static int felix_setup(struct dsa_switch *ds) 27556051948SVladimir Oltean { 27656051948SVladimir Oltean struct ocelot *ocelot = ds->priv; 27756051948SVladimir Oltean struct felix *felix = ocelot_to_felix(ocelot); 27856051948SVladimir Oltean int port, err; 27956051948SVladimir Oltean 28056051948SVladimir Oltean err = felix_init_structs(felix, ds->num_ports); 28156051948SVladimir Oltean if (err) 28256051948SVladimir Oltean return err; 28356051948SVladimir Oltean 28456051948SVladimir Oltean ocelot_init(ocelot); 28556051948SVladimir Oltean 28656051948SVladimir Oltean for (port = 0; port < ds->num_ports; port++) { 28756051948SVladimir Oltean ocelot_init_port(ocelot, port); 28856051948SVladimir Oltean 289*b8fc7177SVladimir Oltean if (dsa_is_cpu_port(ds, port)) 29056051948SVladimir Oltean ocelot_set_cpu_port(ocelot, port, 29156051948SVladimir Oltean OCELOT_TAG_PREFIX_NONE, 29256051948SVladimir Oltean OCELOT_TAG_PREFIX_LONG); 29356051948SVladimir Oltean } 29456051948SVladimir Oltean 29556051948SVladimir Oltean return 0; 29656051948SVladimir Oltean } 29756051948SVladimir Oltean 29856051948SVladimir Oltean static void felix_teardown(struct dsa_switch *ds) 29956051948SVladimir Oltean { 30056051948SVladimir Oltean struct ocelot *ocelot = ds->priv; 30156051948SVladimir Oltean 30256051948SVladimir Oltean /* stop workqueue thread */ 30356051948SVladimir Oltean ocelot_deinit(ocelot); 30456051948SVladimir Oltean } 30556051948SVladimir Oltean 30656051948SVladimir Oltean static const struct dsa_switch_ops felix_switch_ops = { 30756051948SVladimir Oltean .get_tag_protocol = felix_get_tag_protocol, 30856051948SVladimir Oltean .setup = felix_setup, 30956051948SVladimir Oltean .teardown = felix_teardown, 31056051948SVladimir Oltean .set_ageing_time = felix_set_ageing_time, 31156051948SVladimir Oltean .get_strings = felix_get_strings, 31256051948SVladimir Oltean .get_ethtool_stats = felix_get_ethtool_stats, 31356051948SVladimir Oltean .get_sset_count = felix_get_sset_count, 31456051948SVladimir Oltean .get_ts_info = felix_get_ts_info, 31556051948SVladimir Oltean .adjust_link = felix_adjust_link, 31656051948SVladimir Oltean .port_enable = felix_port_enable, 31756051948SVladimir Oltean .port_disable = felix_port_disable, 31856051948SVladimir Oltean .port_fdb_dump = felix_fdb_dump, 31956051948SVladimir Oltean .port_fdb_add = felix_fdb_add, 32056051948SVladimir Oltean .port_fdb_del = felix_fdb_del, 32156051948SVladimir Oltean .port_bridge_join = felix_bridge_join, 32256051948SVladimir Oltean .port_bridge_leave = felix_bridge_leave, 32356051948SVladimir Oltean .port_stp_state_set = felix_bridge_stp_state_set, 32456051948SVladimir Oltean .port_vlan_prepare = felix_vlan_prepare, 32556051948SVladimir Oltean .port_vlan_filtering = felix_vlan_filtering, 32656051948SVladimir Oltean .port_vlan_add = felix_vlan_add, 32756051948SVladimir Oltean .port_vlan_del = felix_vlan_del, 32856051948SVladimir Oltean }; 32956051948SVladimir Oltean 33056051948SVladimir Oltean static struct felix_info *felix_instance_tbl[] = { 33156051948SVladimir Oltean [FELIX_INSTANCE_VSC9959] = &felix_info_vsc9959, 33256051948SVladimir Oltean }; 33356051948SVladimir Oltean 33456051948SVladimir Oltean static int felix_pci_probe(struct pci_dev *pdev, 33556051948SVladimir Oltean const struct pci_device_id *id) 33656051948SVladimir Oltean { 33756051948SVladimir Oltean enum felix_instance instance = id->driver_data; 33856051948SVladimir Oltean struct dsa_switch *ds; 33956051948SVladimir Oltean struct ocelot *ocelot; 34056051948SVladimir Oltean struct felix *felix; 34156051948SVladimir Oltean int err; 34256051948SVladimir Oltean 34356051948SVladimir Oltean err = pci_enable_device(pdev); 34456051948SVladimir Oltean if (err) { 34556051948SVladimir Oltean dev_err(&pdev->dev, "device enable failed\n"); 34656051948SVladimir Oltean goto err_pci_enable; 34756051948SVladimir Oltean } 34856051948SVladimir Oltean 34956051948SVladimir Oltean /* set up for high or low dma */ 35056051948SVladimir Oltean err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64)); 35156051948SVladimir Oltean if (err) { 35256051948SVladimir Oltean err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32)); 35356051948SVladimir Oltean if (err) { 35456051948SVladimir Oltean dev_err(&pdev->dev, 35556051948SVladimir Oltean "DMA configuration failed: 0x%x\n", err); 35656051948SVladimir Oltean goto err_dma; 35756051948SVladimir Oltean } 35856051948SVladimir Oltean } 35956051948SVladimir Oltean 36056051948SVladimir Oltean felix = kzalloc(sizeof(struct felix), GFP_KERNEL); 36156051948SVladimir Oltean if (!felix) { 36256051948SVladimir Oltean err = -ENOMEM; 36356051948SVladimir Oltean dev_err(&pdev->dev, "Failed to allocate driver memory\n"); 36456051948SVladimir Oltean goto err_alloc_felix; 36556051948SVladimir Oltean } 36656051948SVladimir Oltean 36756051948SVladimir Oltean pci_set_drvdata(pdev, felix); 36856051948SVladimir Oltean ocelot = &felix->ocelot; 36956051948SVladimir Oltean ocelot->dev = &pdev->dev; 37056051948SVladimir Oltean felix->pdev = pdev; 37156051948SVladimir Oltean felix->info = felix_instance_tbl[instance]; 37256051948SVladimir Oltean 37356051948SVladimir Oltean pci_set_master(pdev); 37456051948SVladimir Oltean 37556051948SVladimir Oltean ds = kzalloc(sizeof(struct dsa_switch), GFP_KERNEL); 37656051948SVladimir Oltean if (!ds) { 37756051948SVladimir Oltean err = -ENOMEM; 37856051948SVladimir Oltean dev_err(&pdev->dev, "Failed to allocate DSA switch\n"); 37956051948SVladimir Oltean goto err_alloc_ds; 38056051948SVladimir Oltean } 38156051948SVladimir Oltean 38256051948SVladimir Oltean ds->dev = &pdev->dev; 38356051948SVladimir Oltean ds->num_ports = felix->info->num_ports; 38456051948SVladimir Oltean ds->ops = &felix_switch_ops; 38556051948SVladimir Oltean ds->priv = ocelot; 38656051948SVladimir Oltean felix->ds = ds; 38756051948SVladimir Oltean 38856051948SVladimir Oltean err = dsa_register_switch(ds); 38956051948SVladimir Oltean if (err) { 39056051948SVladimir Oltean dev_err(&pdev->dev, "Failed to register DSA switch: %d\n", err); 39156051948SVladimir Oltean goto err_register_ds; 39256051948SVladimir Oltean } 39356051948SVladimir Oltean 39456051948SVladimir Oltean return 0; 39556051948SVladimir Oltean 39656051948SVladimir Oltean err_register_ds: 39756051948SVladimir Oltean kfree(ds); 39856051948SVladimir Oltean err_alloc_ds: 39956051948SVladimir Oltean err_alloc_felix: 40056051948SVladimir Oltean kfree(felix); 40156051948SVladimir Oltean err_dma: 40256051948SVladimir Oltean pci_disable_device(pdev); 40356051948SVladimir Oltean err_pci_enable: 40456051948SVladimir Oltean return err; 40556051948SVladimir Oltean } 40656051948SVladimir Oltean 40756051948SVladimir Oltean static void felix_pci_remove(struct pci_dev *pdev) 40856051948SVladimir Oltean { 40956051948SVladimir Oltean struct felix *felix; 41056051948SVladimir Oltean 41156051948SVladimir Oltean felix = pci_get_drvdata(pdev); 41256051948SVladimir Oltean 41356051948SVladimir Oltean dsa_unregister_switch(felix->ds); 41456051948SVladimir Oltean 41556051948SVladimir Oltean kfree(felix->ds); 41656051948SVladimir Oltean kfree(felix); 41756051948SVladimir Oltean 41856051948SVladimir Oltean pci_disable_device(pdev); 41956051948SVladimir Oltean } 42056051948SVladimir Oltean 42156051948SVladimir Oltean static struct pci_device_id felix_ids[] = { 42256051948SVladimir Oltean { 42356051948SVladimir Oltean /* NXP LS1028A */ 42456051948SVladimir Oltean PCI_DEVICE(PCI_VENDOR_ID_FREESCALE, 0xEEF0), 42556051948SVladimir Oltean .driver_data = FELIX_INSTANCE_VSC9959, 42656051948SVladimir Oltean }, 42756051948SVladimir Oltean { 0, } 42856051948SVladimir Oltean }; 42956051948SVladimir Oltean MODULE_DEVICE_TABLE(pci, felix_ids); 43056051948SVladimir Oltean 43156051948SVladimir Oltean static struct pci_driver felix_pci_driver = { 43256051948SVladimir Oltean .name = KBUILD_MODNAME, 43356051948SVladimir Oltean .id_table = felix_ids, 43456051948SVladimir Oltean .probe = felix_pci_probe, 43556051948SVladimir Oltean .remove = felix_pci_remove, 43656051948SVladimir Oltean }; 43756051948SVladimir Oltean 43856051948SVladimir Oltean module_pci_driver(felix_pci_driver); 43956051948SVladimir Oltean 44056051948SVladimir Oltean MODULE_DESCRIPTION("Felix Switch driver"); 44156051948SVladimir Oltean MODULE_LICENSE("GPL v2"); 442