brintos

brintos / linux-shallow public Read only

0
0
Text · 15.4 KiB · 7a83389 Raw
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