515 lines · c
1/*2 * AMD 10Gb Ethernet driver3 *4 * This file is available to you under your choice of the following two5 * licenses:6 *7 * License 1: GPLv28 *9 * Copyright (c) 2016 Advanced Micro Devices, Inc.10 *11 * This file is free software; you may copy, redistribute and/or modify12 * it under the terms of the GNU General Public License as published by13 * the Free Software Foundation, either version 2 of the License, or (at14 * your option) any later version.15 *16 * This file is distributed in the hope that it will be useful, but17 * WITHOUT ANY WARRANTY; without even the implied warranty of18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU19 * General Public License for more details.20 *21 * You should have received a copy of the GNU General Public License22 * along with this program. If not, see <http://www.gnu.org/licenses/>.23 *24 * This file incorporates work covered by the following copyright and25 * permission notice:26 * The Synopsys DWC ETHER XGMAC Software Driver and documentation27 * (hereinafter "Software") is an unsupported proprietary work of Synopsys,28 * Inc. unless otherwise expressly agreed to in writing between Synopsys29 * and you.30 *31 * The Software IS NOT an item of Licensed Software or Licensed Product32 * under any End User Software License Agreement or Agreement for Licensed33 * Product with Synopsys or any supplement thereto. Permission is hereby34 * granted, free of charge, to any person obtaining a copy of this software35 * annotated with this license and the Software, to deal in the Software36 * without restriction, including without limitation the rights to use,37 * copy, modify, merge, publish, distribute, sublicense, and/or sell copies38 * of the Software, and to permit persons to whom the Software is furnished39 * to do so, subject to the following conditions:40 *41 * The above copyright notice and this permission notice shall be included42 * in all copies or substantial portions of the Software.43 *44 * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS"45 * BASIS AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED46 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A47 * PARTICULAR PURPOSE ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS48 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR49 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF50 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS51 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN52 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)53 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF54 * THE POSSIBILITY OF SUCH DAMAGE.55 *56 *57 * License 2: Modified BSD58 *59 * Copyright (c) 2016 Advanced Micro Devices, Inc.60 * All rights reserved.61 *62 * Redistribution and use in source and binary forms, with or without63 * modification, are permitted provided that the following conditions are met:64 * * Redistributions of source code must retain the above copyright65 * notice, this list of conditions and the following disclaimer.66 * * Redistributions in binary form must reproduce the above copyright67 * notice, this list of conditions and the following disclaimer in the68 * documentation and/or other materials provided with the distribution.69 * * Neither the name of Advanced Micro Devices, Inc. nor the70 * names of its contributors may be used to endorse or promote products71 * derived from this software without specific prior written permission.72 *73 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"74 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE75 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE76 * ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY77 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES78 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;79 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND80 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT81 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF82 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.83 *84 * This file incorporates work covered by the following copyright and85 * permission notice:86 * The Synopsys DWC ETHER XGMAC Software Driver and documentation87 * (hereinafter "Software") is an unsupported proprietary work of Synopsys,88 * Inc. unless otherwise expressly agreed to in writing between Synopsys89 * and you.90 *91 * The Software IS NOT an item of Licensed Software or Licensed Product92 * under any End User Software License Agreement or Agreement for Licensed93 * Product with Synopsys or any supplement thereto. Permission is hereby94 * granted, free of charge, to any person obtaining a copy of this software95 * annotated with this license and the Software, to deal in the Software96 * without restriction, including without limitation the rights to use,97 * copy, modify, merge, publish, distribute, sublicense, and/or sell copies98 * of the Software, and to permit persons to whom the Software is furnished99 * to do so, subject to the following conditions:100 *101 * The above copyright notice and this permission notice shall be included102 * in all copies or substantial portions of the Software.103 *104 * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS"105 * BASIS AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED106 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A107 * PARTICULAR PURPOSE ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS108 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR109 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF110 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS111 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN112 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)113 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF114 * THE POSSIBILITY OF SUCH DAMAGE.115 */116 117#include <linux/module.h>118#include <linux/interrupt.h>119#include <linux/kmod.h>120#include <linux/delay.h>121#include <linux/completion.h>122#include <linux/mutex.h>123 124#include "xgbe.h"125#include "xgbe-common.h"126 127#define XGBE_ABORT_COUNT 500128#define XGBE_DISABLE_COUNT 1000129 130#define XGBE_STD_SPEED 1131 132#define XGBE_INTR_RX_FULL BIT(IC_RAW_INTR_STAT_RX_FULL_INDEX)133#define XGBE_INTR_TX_EMPTY BIT(IC_RAW_INTR_STAT_TX_EMPTY_INDEX)134#define XGBE_INTR_TX_ABRT BIT(IC_RAW_INTR_STAT_TX_ABRT_INDEX)135#define XGBE_INTR_STOP_DET BIT(IC_RAW_INTR_STAT_STOP_DET_INDEX)136#define XGBE_DEFAULT_INT_MASK (XGBE_INTR_RX_FULL | \137 XGBE_INTR_TX_EMPTY | \138 XGBE_INTR_TX_ABRT | \139 XGBE_INTR_STOP_DET)140 141#define XGBE_I2C_READ BIT(8)142#define XGBE_I2C_STOP BIT(9)143 144static int xgbe_i2c_abort(struct xgbe_prv_data *pdata)145{146 unsigned int wait = XGBE_ABORT_COUNT;147 148 /* Must be enabled to recognize the abort request */149 XI2C_IOWRITE_BITS(pdata, IC_ENABLE, EN, 1);150 151 /* Issue the abort */152 XI2C_IOWRITE_BITS(pdata, IC_ENABLE, ABORT, 1);153 154 while (wait--) {155 if (!XI2C_IOREAD_BITS(pdata, IC_ENABLE, ABORT))156 return 0;157 158 usleep_range(500, 600);159 }160 161 return -EBUSY;162}163 164static int xgbe_i2c_set_enable(struct xgbe_prv_data *pdata, bool enable)165{166 unsigned int wait = XGBE_DISABLE_COUNT;167 unsigned int mode = enable ? 1 : 0;168 169 while (wait--) {170 XI2C_IOWRITE_BITS(pdata, IC_ENABLE, EN, mode);171 if (XI2C_IOREAD_BITS(pdata, IC_ENABLE_STATUS, EN) == mode)172 return 0;173 174 usleep_range(100, 110);175 }176 177 return -EBUSY;178}179 180static int xgbe_i2c_disable(struct xgbe_prv_data *pdata)181{182 unsigned int ret;183 184 ret = xgbe_i2c_set_enable(pdata, false);185 if (ret) {186 /* Disable failed, try an abort */187 ret = xgbe_i2c_abort(pdata);188 if (ret)189 return ret;190 191 /* Abort succeeded, try to disable again */192 ret = xgbe_i2c_set_enable(pdata, false);193 }194 195 return ret;196}197 198static int xgbe_i2c_enable(struct xgbe_prv_data *pdata)199{200 return xgbe_i2c_set_enable(pdata, true);201}202 203static void xgbe_i2c_clear_all_interrupts(struct xgbe_prv_data *pdata)204{205 XI2C_IOREAD(pdata, IC_CLR_INTR);206}207 208static void xgbe_i2c_disable_interrupts(struct xgbe_prv_data *pdata)209{210 XI2C_IOWRITE(pdata, IC_INTR_MASK, 0);211}212 213static void xgbe_i2c_enable_interrupts(struct xgbe_prv_data *pdata)214{215 XI2C_IOWRITE(pdata, IC_INTR_MASK, XGBE_DEFAULT_INT_MASK);216}217 218static void xgbe_i2c_write(struct xgbe_prv_data *pdata)219{220 struct xgbe_i2c_op_state *state = &pdata->i2c.op_state;221 unsigned int tx_slots;222 unsigned int cmd;223 224 /* Configured to never receive Rx overflows, so fill up Tx fifo */225 tx_slots = pdata->i2c.tx_fifo_size - XI2C_IOREAD(pdata, IC_TXFLR);226 while (tx_slots && state->tx_len) {227 if (state->op->cmd == XGBE_I2C_CMD_READ)228 cmd = XGBE_I2C_READ;229 else230 cmd = *state->tx_buf++;231 232 if (state->tx_len == 1)233 XI2C_SET_BITS(cmd, IC_DATA_CMD, STOP, 1);234 235 XI2C_IOWRITE(pdata, IC_DATA_CMD, cmd);236 237 tx_slots--;238 state->tx_len--;239 }240 241 /* No more Tx operations, so ignore TX_EMPTY and return */242 if (!state->tx_len)243 XI2C_IOWRITE_BITS(pdata, IC_INTR_MASK, TX_EMPTY, 0);244}245 246static void xgbe_i2c_read(struct xgbe_prv_data *pdata)247{248 struct xgbe_i2c_op_state *state = &pdata->i2c.op_state;249 unsigned int rx_slots;250 251 /* Anything to be read? */252 if (state->op->cmd != XGBE_I2C_CMD_READ)253 return;254 255 rx_slots = XI2C_IOREAD(pdata, IC_RXFLR);256 while (rx_slots && state->rx_len) {257 *state->rx_buf++ = XI2C_IOREAD(pdata, IC_DATA_CMD);258 state->rx_len--;259 rx_slots--;260 }261}262 263static void xgbe_i2c_clear_isr_interrupts(struct xgbe_prv_data *pdata,264 unsigned int isr)265{266 struct xgbe_i2c_op_state *state = &pdata->i2c.op_state;267 268 if (isr & XGBE_INTR_TX_ABRT) {269 state->tx_abort_source = XI2C_IOREAD(pdata, IC_TX_ABRT_SOURCE);270 XI2C_IOREAD(pdata, IC_CLR_TX_ABRT);271 }272 273 if (isr & XGBE_INTR_STOP_DET)274 XI2C_IOREAD(pdata, IC_CLR_STOP_DET);275}276 277static void xgbe_i2c_isr_bh_work(struct work_struct *work)278{279 struct xgbe_prv_data *pdata = from_work(pdata, work, i2c_bh_work);280 struct xgbe_i2c_op_state *state = &pdata->i2c.op_state;281 unsigned int isr;282 283 isr = XI2C_IOREAD(pdata, IC_RAW_INTR_STAT);284 if (!isr)285 goto reissue_check;286 287 netif_dbg(pdata, intr, pdata->netdev,288 "I2C interrupt received: status=%#010x\n", isr);289 290 xgbe_i2c_clear_isr_interrupts(pdata, isr);291 292 if (isr & XGBE_INTR_TX_ABRT) {293 netif_dbg(pdata, link, pdata->netdev,294 "I2C TX_ABRT received (%#010x) for target %#04x\n",295 state->tx_abort_source, state->op->target);296 297 xgbe_i2c_disable_interrupts(pdata);298 299 state->ret = -EIO;300 goto out;301 }302 303 /* Check for data in the Rx fifo */304 xgbe_i2c_read(pdata);305 306 /* Fill up the Tx fifo next */307 xgbe_i2c_write(pdata);308 309out:310 /* Complete on an error or STOP condition */311 if (state->ret || XI2C_GET_BITS(isr, IC_RAW_INTR_STAT, STOP_DET))312 complete(&pdata->i2c_complete);313 314reissue_check:315 /* Reissue interrupt if status is not clear */316 if (pdata->vdata->irq_reissue_support)317 XP_IOWRITE(pdata, XP_INT_REISSUE_EN, 1 << 2);318}319 320static irqreturn_t xgbe_i2c_isr(int irq, void *data)321{322 struct xgbe_prv_data *pdata = (struct xgbe_prv_data *)data;323 324 if (pdata->isr_as_bh_work)325 queue_work(system_bh_wq, &pdata->i2c_bh_work);326 else327 xgbe_i2c_isr_bh_work(&pdata->i2c_bh_work);328 329 return IRQ_HANDLED;330}331 332static void xgbe_i2c_set_mode(struct xgbe_prv_data *pdata)333{334 unsigned int reg;335 336 reg = XI2C_IOREAD(pdata, IC_CON);337 XI2C_SET_BITS(reg, IC_CON, MASTER_MODE, 1);338 XI2C_SET_BITS(reg, IC_CON, SLAVE_DISABLE, 1);339 XI2C_SET_BITS(reg, IC_CON, RESTART_EN, 1);340 XI2C_SET_BITS(reg, IC_CON, SPEED, XGBE_STD_SPEED);341 XI2C_SET_BITS(reg, IC_CON, RX_FIFO_FULL_HOLD, 1);342 XI2C_IOWRITE(pdata, IC_CON, reg);343}344 345static void xgbe_i2c_get_features(struct xgbe_prv_data *pdata)346{347 struct xgbe_i2c *i2c = &pdata->i2c;348 unsigned int reg;349 350 reg = XI2C_IOREAD(pdata, IC_COMP_PARAM_1);351 i2c->max_speed_mode = XI2C_GET_BITS(reg, IC_COMP_PARAM_1,352 MAX_SPEED_MODE);353 i2c->rx_fifo_size = XI2C_GET_BITS(reg, IC_COMP_PARAM_1,354 RX_BUFFER_DEPTH);355 i2c->tx_fifo_size = XI2C_GET_BITS(reg, IC_COMP_PARAM_1,356 TX_BUFFER_DEPTH);357 358 if (netif_msg_probe(pdata))359 dev_dbg(pdata->dev, "I2C features: %s=%u, %s=%u, %s=%u\n",360 "MAX_SPEED_MODE", i2c->max_speed_mode,361 "RX_BUFFER_DEPTH", i2c->rx_fifo_size,362 "TX_BUFFER_DEPTH", i2c->tx_fifo_size);363}364 365static void xgbe_i2c_set_target(struct xgbe_prv_data *pdata, unsigned int addr)366{367 XI2C_IOWRITE(pdata, IC_TAR, addr);368}369 370static irqreturn_t xgbe_i2c_combined_isr(struct xgbe_prv_data *pdata)371{372 xgbe_i2c_isr_bh_work(&pdata->i2c_bh_work);373 374 return IRQ_HANDLED;375}376 377static int xgbe_i2c_xfer(struct xgbe_prv_data *pdata, struct xgbe_i2c_op *op)378{379 struct xgbe_i2c_op_state *state = &pdata->i2c.op_state;380 int ret;381 382 mutex_lock(&pdata->i2c_mutex);383 384 reinit_completion(&pdata->i2c_complete);385 386 ret = xgbe_i2c_disable(pdata);387 if (ret) {388 netdev_err(pdata->netdev, "failed to disable i2c master\n");389 goto unlock;390 }391 392 xgbe_i2c_set_target(pdata, op->target);393 394 memset(state, 0, sizeof(*state));395 state->op = op;396 state->tx_len = op->len;397 state->tx_buf = op->buf;398 state->rx_len = op->len;399 state->rx_buf = op->buf;400 401 xgbe_i2c_clear_all_interrupts(pdata);402 ret = xgbe_i2c_enable(pdata);403 if (ret) {404 netdev_err(pdata->netdev, "failed to enable i2c master\n");405 goto unlock;406 }407 408 /* Enabling the interrupts will cause the TX FIFO empty interrupt to409 * fire and begin to process the command via the ISR.410 */411 xgbe_i2c_enable_interrupts(pdata);412 413 if (!wait_for_completion_timeout(&pdata->i2c_complete, HZ)) {414 netdev_err(pdata->netdev, "i2c operation timed out\n");415 ret = -ETIMEDOUT;416 goto disable;417 }418 419 ret = state->ret;420 if (ret) {421 if (state->tx_abort_source & IC_TX_ABRT_7B_ADDR_NOACK)422 ret = -ENOTCONN;423 else if (state->tx_abort_source & IC_TX_ABRT_ARB_LOST)424 ret = -EAGAIN;425 }426 427disable:428 xgbe_i2c_disable_interrupts(pdata);429 xgbe_i2c_disable(pdata);430 431unlock:432 mutex_unlock(&pdata->i2c_mutex);433 434 return ret;435}436 437static void xgbe_i2c_stop(struct xgbe_prv_data *pdata)438{439 if (!pdata->i2c.started)440 return;441 442 netif_dbg(pdata, link, pdata->netdev, "stopping I2C\n");443 444 pdata->i2c.started = 0;445 446 xgbe_i2c_disable_interrupts(pdata);447 xgbe_i2c_disable(pdata);448 xgbe_i2c_clear_all_interrupts(pdata);449 450 if (pdata->dev_irq != pdata->i2c_irq) {451 devm_free_irq(pdata->dev, pdata->i2c_irq, pdata);452 cancel_work_sync(&pdata->i2c_bh_work);453 }454}455 456static int xgbe_i2c_start(struct xgbe_prv_data *pdata)457{458 int ret;459 460 if (pdata->i2c.started)461 return 0;462 463 netif_dbg(pdata, link, pdata->netdev, "starting I2C\n");464 465 /* If we have a separate I2C irq, enable it */466 if (pdata->dev_irq != pdata->i2c_irq) {467 INIT_WORK(&pdata->i2c_bh_work, xgbe_i2c_isr_bh_work);468 469 ret = devm_request_irq(pdata->dev, pdata->i2c_irq,470 xgbe_i2c_isr, 0, pdata->i2c_name,471 pdata);472 if (ret) {473 netdev_err(pdata->netdev, "i2c irq request failed\n");474 return ret;475 }476 }477 478 pdata->i2c.started = 1;479 480 return 0;481}482 483static int xgbe_i2c_init(struct xgbe_prv_data *pdata)484{485 int ret;486 487 xgbe_i2c_disable_interrupts(pdata);488 489 ret = xgbe_i2c_disable(pdata);490 if (ret) {491 dev_err(pdata->dev, "failed to disable i2c master\n");492 return ret;493 }494 495 xgbe_i2c_get_features(pdata);496 497 xgbe_i2c_set_mode(pdata);498 499 xgbe_i2c_clear_all_interrupts(pdata);500 501 return 0;502}503 504void xgbe_init_function_ptrs_i2c(struct xgbe_i2c_if *i2c_if)505{506 i2c_if->i2c_init = xgbe_i2c_init;507 508 i2c_if->i2c_start = xgbe_i2c_start;509 i2c_if->i2c_stop = xgbe_i2c_stop;510 511 i2c_if->i2c_xfer = xgbe_i2c_xfer;512 513 i2c_if->i2c_isr = xgbe_i2c_combined_isr;514}515