1 /* 2 * This file and its contents are supplied under the terms of the 3 * Common Development and Distribution License ("CDDL"), version 1.0. 4 * You may only use this file in accordance with the terms of version 5 * 1.0 of the CDDL. 6 * 7 * A full copy of the text of the CDDL should have accompanied this 8 * source. A copy of the CDDL is also available via the Internet at 9 * http://www.illumos.org/license/CDDL. 10 */ 11 12 /* 13 * This file is part of the Chelsio T4 support code. 14 * 15 * Copyright (C) 2011-2013 Chelsio Communications. All rights reserved. 16 * 17 * This program is distributed in the hope that it will be useful, but WITHOUT 18 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 19 * FITNESS FOR A PARTICULAR PURPOSE. See the LICENSE file included in this 20 * release for licensing terms and conditions. 21 */ 22 23 #include <sys/ddi.h> 24 #include <sys/sunddi.h> 25 #include <sys/modctl.h> 26 #include <sys/conf.h> 27 #include <sys/atomic.h> 28 #include <sys/ethernet.h> 29 #include <sys/mac_provider.h> 30 #include <sys/mac_ether.h> 31 32 /* 33 * NOTE: The "real" NIC driver is in the nexus. This is just a thin wrapper 34 * whose only purpose is to register the mac. 35 */ 36 #include "shared.h" 37 #include "version.h" 38 39 struct port_info_stub { 40 PORT_INFO_HDR; 41 }; 42 43 static struct cb_ops cxgbe_cb_ops = { 44 .cb_open = nulldev, 45 .cb_close = nulldev, 46 .cb_strategy = nodev, 47 .cb_print = nodev, 48 .cb_dump = nodev, 49 .cb_read = nodev, 50 .cb_write = nodev, 51 .cb_ioctl = nodev, 52 .cb_devmap = nodev, 53 .cb_mmap = nodev, 54 .cb_segmap = nodev, 55 .cb_chpoll = nochpoll, 56 .cb_prop_op = ddi_prop_op, 57 .cb_flag = D_MP, 58 .cb_rev = CB_REV, 59 .cb_aread = nodev, 60 .cb_awrite = nodev 61 }; 62 63 static int cxgbe_devo_attach(dev_info_t *, ddi_attach_cmd_t); 64 static int cxgbe_devo_detach(dev_info_t *, ddi_detach_cmd_t); 65 struct dev_ops cxgbe_dev_ops = { 66 .devo_rev = DEVO_REV, 67 .devo_identify = nulldev, 68 .devo_probe = nulldev, 69 .devo_attach = cxgbe_devo_attach, 70 .devo_detach = cxgbe_devo_detach, 71 .devo_reset = nodev, 72 .devo_cb_ops = &cxgbe_cb_ops, 73 }; 74 75 static struct modldrv modldrv = { 76 .drv_modops = &mod_driverops, 77 .drv_linkinfo = "Chelsio T4 NIC " DRV_VERSION, 78 .drv_dev_ops = &cxgbe_dev_ops 79 }; 80 81 static struct modlinkage modlinkage = { 82 .ml_rev = MODREV_1, 83 .ml_linkage = {&modldrv, NULL}, 84 }; 85 86 int 87 _init(void) 88 { 89 int rc; 90 91 mac_init_ops(&cxgbe_dev_ops, T4_PORT_NAME); 92 rc = mod_install(&modlinkage); 93 if (rc != 0) 94 mac_fini_ops(&cxgbe_dev_ops); 95 96 return (rc); 97 } 98 99 int 100 _fini(void) 101 { 102 int rc; 103 104 rc = mod_remove(&modlinkage); 105 if (rc != 0) 106 return (rc); 107 108 mac_fini_ops(&cxgbe_dev_ops); 109 return (0); 110 } 111 112 int 113 _info(struct modinfo *mi) 114 { 115 return (mod_info(&modlinkage, mi)); 116 } 117 118 static int 119 cxgbe_devo_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 120 { 121 struct port_info_stub *pi; 122 mac_register_t *mac; 123 mac_handle_t mh; 124 int rc; 125 126 if (cmd != DDI_ATTACH) 127 return (DDI_FAILURE); 128 129 pi = ddi_get_parent_data(dip); 130 if (pi == NULL) 131 return (DDI_FAILURE); 132 133 mac = mac_alloc(MAC_VERSION); 134 if (mac == NULL) { 135 cmn_err(CE_WARN, "%s%d: failed to allocate version %d mac.", 136 ddi_driver_name(pi->dip), ddi_get_instance(pi->dip), 137 MAC_VERSION); 138 return (DDI_FAILURE); 139 } 140 141 mac->m_type_ident = MAC_PLUGIN_IDENT_ETHER; 142 mac->m_driver = pi; 143 mac->m_dip = dip; 144 mac->m_src_addr = pi->hw_addr; 145 mac->m_callbacks = pi->mc; 146 mac->m_max_sdu = pi->mtu; 147 mac->m_priv_props = pi->props; 148 mac->m_margin = 22; /* TODO: mac_register(9s) and onnv code disagree */ 149 150 rc = mac_register(mac, &mh); 151 mac_free(mac); 152 if (rc != 0) { 153 cmn_err(CE_WARN, "%s%d: failed to register version %d mac.", 154 ddi_driver_name(pi->dip), ddi_get_instance(pi->dip), 155 MAC_VERSION); 156 return (DDI_FAILURE); 157 } 158 pi->mh = mh; 159 160 /* 161 * Link state from this point onwards to the time interface is plumbed, 162 * should be set to LINK_STATE_UNKNOWN. The mac should be updated about 163 * the link state as either LINK_STATE_UP or LINK_STATE_DOWN based on 164 * the actual link state detection after interface plumb. 165 */ 166 mac_link_update(mh, LINK_STATE_UNKNOWN); 167 168 ddi_report_dev(dip); 169 170 return (DDI_SUCCESS); 171 } 172 173 static int 174 cxgbe_devo_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 175 { 176 struct port_info_stub *pi; 177 mac_handle_t mh; 178 179 if (cmd != DDI_DETACH) 180 return (DDI_FAILURE); 181 182 pi = ddi_get_parent_data(dip); 183 if (pi == NULL) 184 return (DDI_FAILURE); 185 186 mh = pi->mh; 187 pi->mh = NULL; 188 189 return (mac_unregister(mh)); 190 } 191