File Index
Files and directories
Sign in
FILE

hbg_hw.c

File preview with syntax highlighting.

linux-6.19.14/drivers/net/ethernet/hisilicon/hibmcge/hbg_hw.c C
  1// SPDX-License-Identifier: GPL-2.0+
  2// Copyright (c) 2024 Hisilicon Limited.
  3
  4#include <linux/etherdevice.h>
  5#include <linux/ethtool.h>
  6#include <linux/if_vlan.h>
  7#include <linux/iopoll.h>
  8#include <linux/minmax.h>
  9#include "hbg_common.h"
 10#include "hbg_hw.h"
 11#include "hbg_reg.h"
 12
 13#define HBG_HW_EVENT_WAIT_TIMEOUT_US	(2 * 1000 * 1000)
 14#define HBG_HW_EVENT_WAIT_INTERVAL_US	(10 * 1000)
 15#define HBG_MAC_LINK_WAIT_TIMEOUT_US	(500 * 1000)
 16#define HBG_MAC_LINK_WAIT_INTERVAL_US	(5 * 1000)
 17/* little endian or big endian.
 18 * ctrl means packet description, data means skb packet data
 19 */
 20#define HBG_ENDIAN_CTRL_LE_DATA_BE	0x0
 21#define HBG_PCU_FRAME_LEN_PLUS 4
 22
 23#define HBG_FIFO_TX_FULL_THRSLD		0x3F0
 24#define HBG_FIFO_TX_EMPTY_THRSLD	0x1F0
 25#define HBG_FIFO_RX_FULL_THRSLD		0x240
 26#define HBG_FIFO_RX_EMPTY_THRSLD	0x190
 27#define HBG_CFG_FIFO_FULL_THRSLD	0x10
 28#define HBG_CFG_FIFO_EMPTY_THRSLD	0x01
 29
 30static bool hbg_hw_spec_is_valid(struct hbg_priv *priv)
 31{
 32	return hbg_reg_read(priv, HBG_REG_SPEC_VALID_ADDR) &&
 33	       !hbg_reg_read(priv, HBG_REG_EVENT_REQ_ADDR);
 34}
 35
 36int hbg_hw_event_notify(struct hbg_priv *priv,
 37			enum hbg_hw_event_type event_type)
 38{
 39	bool is_valid;
 40	int ret;
 41
 42	if (test_and_set_bit(HBG_NIC_STATE_EVENT_HANDLING, &priv->state))
 43		return -EBUSY;
 44
 45	/* notify */
 46	hbg_reg_write(priv, HBG_REG_EVENT_REQ_ADDR, event_type);
 47
 48	ret = read_poll_timeout(hbg_hw_spec_is_valid, is_valid, is_valid,
 49				HBG_HW_EVENT_WAIT_INTERVAL_US,
 50				HBG_HW_EVENT_WAIT_TIMEOUT_US,
 51				HBG_HW_EVENT_WAIT_INTERVAL_US, priv);
 52
 53	clear_bit(HBG_NIC_STATE_EVENT_HANDLING, &priv->state);
 54
 55	if (ret)
 56		dev_err(&priv->pdev->dev,
 57			"event %d wait timeout\n", event_type);
 58
 59	return ret;
 60}
 61
 62static int hbg_hw_dev_specs_init(struct hbg_priv *priv)
 63{
 64	struct hbg_dev_specs *specs = &priv->dev_specs;
 65	u64 mac_addr;
 66
 67	if (!hbg_hw_spec_is_valid(priv)) {
 68		dev_err(&priv->pdev->dev, "dev_specs not init\n");
 69		return -EINVAL;
 70	}
 71
 72	specs->mac_id = hbg_reg_read(priv, HBG_REG_MAC_ID_ADDR);
 73	specs->phy_addr = hbg_reg_read(priv, HBG_REG_PHY_ID_ADDR);
 74	specs->mdio_frequency = hbg_reg_read(priv, HBG_REG_MDIO_FREQ_ADDR);
 75	specs->max_mtu = hbg_reg_read(priv, HBG_REG_MAX_MTU_ADDR);
 76	specs->min_mtu = hbg_reg_read(priv, HBG_REG_MIN_MTU_ADDR);
 77	specs->vlan_layers = hbg_reg_read(priv, HBG_REG_VLAN_LAYERS_ADDR);
 78	specs->rx_fifo_num = hbg_reg_read(priv, HBG_REG_RX_FIFO_NUM_ADDR);
 79	specs->tx_fifo_num = hbg_reg_read(priv, HBG_REG_TX_FIFO_NUM_ADDR);
 80	specs->uc_mac_num = hbg_reg_read(priv, HBG_REG_UC_MAC_NUM_ADDR);
 81
 82	mac_addr = hbg_reg_read64(priv, HBG_REG_MAC_ADDR_ADDR);
 83	u64_to_ether_addr(mac_addr, (u8 *)specs->mac_addr.sa_data);
 84
 85	if (!is_valid_ether_addr((u8 *)specs->mac_addr.sa_data))
 86		return -EADDRNOTAVAIL;
 87
 88	specs->max_frame_len = HBG_PCU_CACHE_LINE_SIZE + specs->max_mtu;
 89	specs->rx_buf_size = HBG_PACKET_HEAD_SIZE + specs->max_frame_len;
 90	return 0;
 91}
 92
 93u32 hbg_hw_get_irq_status(struct hbg_priv *priv)
 94{
 95	u32 status;
 96
 97	status = hbg_reg_read(priv, HBG_REG_CF_INTRPT_STAT_ADDR);
 98
 99	hbg_field_modify(status, HBG_INT_MSK_TX_B,
100			 hbg_reg_read(priv, HBG_REG_CF_IND_TXINT_STAT_ADDR));
101	hbg_field_modify(status, HBG_INT_MSK_RX_B,
102			 hbg_reg_read(priv, HBG_REG_CF_IND_RXINT_STAT_ADDR));
103
104	return status;
105}
106
107void hbg_hw_irq_clear(struct hbg_priv *priv, u32 mask)
108{
109	if (FIELD_GET(HBG_INT_MSK_TX_B, mask))
110		return hbg_reg_write(priv, HBG_REG_CF_IND_TXINT_CLR_ADDR, 0x1);
111
112	if (FIELD_GET(HBG_INT_MSK_RX_B, mask))
113		return hbg_reg_write(priv, HBG_REG_CF_IND_RXINT_CLR_ADDR, 0x1);
114
115	return hbg_reg_write(priv, HBG_REG_CF_INTRPT_CLR_ADDR, mask);
116}
117
118bool hbg_hw_irq_is_enabled(struct hbg_priv *priv, u32 mask)
119{
120	if (FIELD_GET(HBG_INT_MSK_TX_B, mask))
121		return hbg_reg_read(priv, HBG_REG_CF_IND_TXINT_MSK_ADDR);
122
123	if (FIELD_GET(HBG_INT_MSK_RX_B, mask))
124		return hbg_reg_read(priv, HBG_REG_CF_IND_RXINT_MSK_ADDR);
125
126	return hbg_reg_read(priv, HBG_REG_CF_INTRPT_MSK_ADDR) & mask;
127}
128
129void hbg_hw_irq_enable(struct hbg_priv *priv, u32 mask, bool enable)
130{
131	u32 value;
132
133	if (FIELD_GET(HBG_INT_MSK_TX_B, mask))
134		return hbg_reg_write(priv,
135				     HBG_REG_CF_IND_TXINT_MSK_ADDR, enable);
136
137	if (FIELD_GET(HBG_INT_MSK_RX_B, mask))
138		return hbg_reg_write(priv,
139				     HBG_REG_CF_IND_RXINT_MSK_ADDR, enable);
140
141	value = hbg_reg_read(priv, HBG_REG_CF_INTRPT_MSK_ADDR);
142	if (enable)
143		value |= mask;
144	else
145		value &= ~mask;
146
147	hbg_reg_write(priv, HBG_REG_CF_INTRPT_MSK_ADDR, value);
148}
149
150void hbg_hw_set_uc_addr(struct hbg_priv *priv, u64 mac_addr, u32 index)
151{
152	u32 addr;
153
154	/* mac addr is u64, so the addr offset is 0x8 */
155	addr = HBG_REG_STATION_ADDR_LOW_2_ADDR + (index * 0x8);
156	hbg_reg_write64(priv, addr, mac_addr);
157}
158
159static void hbg_hw_set_pcu_max_frame_len(struct hbg_priv *priv,
160					 u16 max_frame_len)
161{
162	max_frame_len = max_t(u32, max_frame_len, ETH_DATA_LEN);
163
164	/* lower two bits of value must be set to 0 */
165	max_frame_len = round_up(max_frame_len, HBG_PCU_FRAME_LEN_PLUS);
166
167	hbg_reg_write_field(priv, HBG_REG_MAX_FRAME_LEN_ADDR,
168			    HBG_REG_MAX_FRAME_LEN_M, max_frame_len);
169}
170
171static void hbg_hw_set_mac_max_frame_len(struct hbg_priv *priv,
172					 u16 max_frame_size)
173{
174	hbg_reg_write_field(priv, HBG_REG_MAX_FRAME_SIZE_ADDR,
175			    HBG_REG_MAX_FRAME_LEN_M, max_frame_size);
176}
177
178void hbg_hw_set_mtu(struct hbg_priv *priv, u16 mtu)
179{
180	/* burst_len BIT(29) set to 1 can improve the TX performance.
181	 * But packet drop occurs when mtu > 2000.
182	 * So, BIT(29) reset to 0 when mtu > 2000.
183	 */
184	u32 burst_len_bit = (mtu > 2000) ? 0 : 1;
185	u32 frame_len;
186
187	frame_len = mtu + VLAN_HLEN * priv->dev_specs.vlan_layers +
188		    ETH_HLEN + ETH_FCS_LEN;
189
190	hbg_hw_set_pcu_max_frame_len(priv, frame_len);
191	hbg_hw_set_mac_max_frame_len(priv, frame_len);
192
193	hbg_reg_write_field(priv, HBG_REG_BRUST_LENGTH_ADDR,
194			    HBG_REG_BRUST_LENGTH_B, burst_len_bit);
195}
196
197void hbg_hw_mac_enable(struct hbg_priv *priv, u32 enable)
198{
199	hbg_reg_write_field(priv, HBG_REG_PORT_ENABLE_ADDR,
200			    HBG_REG_PORT_ENABLE_TX_B, enable);
201	hbg_reg_write_field(priv, HBG_REG_PORT_ENABLE_ADDR,
202			    HBG_REG_PORT_ENABLE_RX_B, enable);
203}
204
205u32 hbg_hw_get_fifo_used_num(struct hbg_priv *priv, enum hbg_dir dir)
206{
207	if (dir & HBG_DIR_TX)
208		return hbg_reg_read_field(priv, HBG_REG_CF_CFF_DATA_NUM_ADDR,
209					  HBG_REG_CF_CFF_DATA_NUM_ADDR_TX_M);
210
211	if (dir & HBG_DIR_RX)
212		return hbg_reg_read_field(priv, HBG_REG_CF_CFF_DATA_NUM_ADDR,
213					  HBG_REG_CF_CFF_DATA_NUM_ADDR_RX_M);
214
215	return 0;
216}
217
218void hbg_hw_set_tx_desc(struct hbg_priv *priv, struct hbg_tx_desc *tx_desc)
219{
220	hbg_reg_write(priv, HBG_REG_TX_CFF_ADDR_0_ADDR, tx_desc->word0);
221	hbg_reg_write(priv, HBG_REG_TX_CFF_ADDR_1_ADDR, tx_desc->word1);
222	hbg_reg_write(priv, HBG_REG_TX_CFF_ADDR_2_ADDR, tx_desc->word2);
223	hbg_reg_write(priv, HBG_REG_TX_CFF_ADDR_3_ADDR, tx_desc->word3);
224}
225
226void hbg_hw_fill_buffer(struct hbg_priv *priv, u32 buffer_dma_addr)
227{
228	hbg_reg_write(priv, HBG_REG_RX_CFF_ADDR_ADDR, buffer_dma_addr);
229}
230
231void hbg_hw_adjust_link(struct hbg_priv *priv, u32 speed, u32 duplex)
232{
233	u32 link_status;
234	int ret;
235
236	hbg_hw_mac_enable(priv, HBG_STATUS_DISABLE);
237
238	hbg_reg_write_field(priv, HBG_REG_PORT_MODE_ADDR,
239			    HBG_REG_PORT_MODE_M, speed);
240	hbg_reg_write_field(priv, HBG_REG_DUPLEX_TYPE_ADDR,
241			    HBG_REG_DUPLEX_B, duplex);
242
243	hbg_hw_event_notify(priv, HBG_HW_EVENT_CORE_RESET);
244
245	hbg_hw_mac_enable(priv, HBG_STATUS_ENABLE);
246
247	if (priv->mac.phy_addr == HBG_NO_PHY)
248		return;
249
250	/* wait MAC link up */
251	ret = readl_poll_timeout(priv->io_base + HBG_REG_AN_NEG_STATE_ADDR,
252				 link_status,
253				 FIELD_GET(HBG_REG_AN_NEG_STATE_NP_LINK_OK_B,
254					   link_status),
255				 HBG_MAC_LINK_WAIT_INTERVAL_US,
256				 HBG_MAC_LINK_WAIT_TIMEOUT_US);
257	if (ret)
258		hbg_np_link_fail_task_schedule(priv);
259}
260
261/* only support uc filter */
262void hbg_hw_set_mac_filter_enable(struct hbg_priv *priv, u32 enable)
263{
264	hbg_reg_write_field(priv, HBG_REG_REC_FILT_CTRL_ADDR,
265			    HBG_REG_REC_FILT_CTRL_UC_MATCH_EN_B, enable);
266
267	/* only uc filter is supported, so set all bits of mc mask reg to 1 */
268	hbg_reg_write64(priv, HBG_REG_STATION_ADDR_LOW_MSK_0, U64_MAX);
269	hbg_reg_write64(priv, HBG_REG_STATION_ADDR_LOW_MSK_1, U64_MAX);
270}
271
272void hbg_hw_set_pause_enable(struct hbg_priv *priv, u32 tx_en, u32 rx_en)
273{
274	hbg_reg_write_field(priv, HBG_REG_PAUSE_ENABLE_ADDR,
275			    HBG_REG_PAUSE_ENABLE_TX_B, tx_en);
276	hbg_reg_write_field(priv, HBG_REG_PAUSE_ENABLE_ADDR,
277			    HBG_REG_PAUSE_ENABLE_RX_B, rx_en);
278
279	hbg_reg_write_field(priv, HBG_REG_REC_FILT_CTRL_ADDR,
280			    HBG_REG_REC_FILT_CTRL_PAUSE_FRM_PASS_B, rx_en);
281}
282
283void hbg_hw_get_pause_enable(struct hbg_priv *priv, u32 *tx_en, u32 *rx_en)
284{
285	*tx_en = hbg_reg_read_field(priv, HBG_REG_PAUSE_ENABLE_ADDR,
286				    HBG_REG_PAUSE_ENABLE_TX_B);
287	*rx_en = hbg_reg_read_field(priv, HBG_REG_PAUSE_ENABLE_ADDR,
288				    HBG_REG_PAUSE_ENABLE_RX_B);
289}
290
291void hbg_hw_set_rx_pause_mac_addr(struct hbg_priv *priv, u64 mac_addr)
292{
293	hbg_reg_write64(priv, HBG_REG_FD_FC_ADDR_LOW_ADDR, mac_addr);
294}
295
296static void hbg_hw_set_fifo_thrsld(struct hbg_priv *priv,
297				   u32 full, u32 empty, enum hbg_dir dir)
298{
299	u32 value = 0;
300
301	value |= FIELD_PREP(HBG_REG_FIFO_THRSLD_FULL_M, full);
302	value |= FIELD_PREP(HBG_REG_FIFO_THRSLD_EMPTY_M, empty);
303
304	if (dir & HBG_DIR_TX)
305		hbg_reg_write(priv, HBG_REG_TX_FIFO_THRSLD_ADDR, value);
306
307	if (dir & HBG_DIR_RX)
308		hbg_reg_write(priv, HBG_REG_RX_FIFO_THRSLD_ADDR, value);
309}
310
311static void hbg_hw_set_cfg_fifo_thrsld(struct hbg_priv *priv,
312				       u32 full, u32 empty, enum hbg_dir dir)
313{
314	u32 value;
315
316	value = hbg_reg_read(priv, HBG_REG_CFG_FIFO_THRSLD_ADDR);
317
318	if (dir & HBG_DIR_TX) {
319		value |= FIELD_PREP(HBG_REG_CFG_FIFO_THRSLD_TX_FULL_M, full);
320		value |= FIELD_PREP(HBG_REG_CFG_FIFO_THRSLD_TX_EMPTY_M, empty);
321	}
322
323	if (dir & HBG_DIR_RX) {
324		value |= FIELD_PREP(HBG_REG_CFG_FIFO_THRSLD_RX_FULL_M, full);
325		value |= FIELD_PREP(HBG_REG_CFG_FIFO_THRSLD_RX_EMPTY_M, empty);
326	}
327
328	hbg_reg_write(priv, HBG_REG_CFG_FIFO_THRSLD_ADDR, value);
329}
330
331static void hbg_hw_init_transmit_ctrl(struct hbg_priv *priv)
332{
333	u32 ctrl = 0;
334
335	ctrl |= FIELD_PREP(HBG_REG_TRANSMIT_CTRL_AN_EN_B, HBG_STATUS_ENABLE);
336	ctrl |= FIELD_PREP(HBG_REG_TRANSMIT_CTRL_CRC_ADD_B, HBG_STATUS_ENABLE);
337	ctrl |= FIELD_PREP(HBG_REG_TRANSMIT_CTRL_PAD_EN_B, HBG_STATUS_ENABLE);
338
339	hbg_reg_write(priv, HBG_REG_TRANSMIT_CTRL_ADDR, ctrl);
340}
341
342static void hbg_hw_init_rx_ctrl(struct hbg_priv *priv)
343{
344	u32 ctrl = 0;
345
346	ctrl |= FIELD_PREP(HBG_REG_RX_CTRL_RX_GET_ADDR_MODE_B,
347			   HBG_STATUS_ENABLE);
348	ctrl |= FIELD_PREP(HBG_REG_RX_CTRL_TIME_INF_EN_B, HBG_STATUS_DISABLE);
349	ctrl |= FIELD_PREP(HBG_REG_RX_CTRL_RXBUF_1ST_SKIP_SIZE_M, HBG_RX_SKIP1);
350	ctrl |= FIELD_PREP(HBG_REG_RX_CTRL_RXBUF_1ST_SKIP_SIZE2_M,
351			   HBG_RX_SKIP2);
352	ctrl |= FIELD_PREP(HBG_REG_RX_CTRL_RX_ALIGN_NUM_M, NET_IP_ALIGN);
353	ctrl |= FIELD_PREP(HBG_REG_RX_CTRL_PORT_NUM, priv->dev_specs.mac_id);
354
355	hbg_reg_write(priv, HBG_REG_RX_CTRL_ADDR, ctrl);
356}
357
358static void hbg_hw_init_rx_control(struct hbg_priv *priv)
359{
360	hbg_hw_init_rx_ctrl(priv);
361
362	/* parse from L2 layer */
363	hbg_reg_write_field(priv, HBG_REG_RX_PKT_MODE_ADDR,
364			    HBG_REG_RX_PKT_MODE_PARSE_MODE_M, 0x1);
365
366	hbg_reg_write_field(priv, HBG_REG_RECV_CTRL_ADDR,
367			    HBG_REG_RECV_CTRL_STRIP_PAD_EN_B,
368			    HBG_STATUS_ENABLE);
369	hbg_reg_write_field(priv, HBG_REG_RX_BUF_SIZE_ADDR,
370			    HBG_REG_RX_BUF_SIZE_M, priv->dev_specs.rx_buf_size);
371	hbg_reg_write_field(priv, HBG_REG_CF_CRC_STRIP_ADDR,
372			    HBG_REG_CF_CRC_STRIP_B, HBG_STATUS_DISABLE);
373}
374
375int hbg_hw_init(struct hbg_priv *priv)
376{
377	int ret;
378
379	ret = hbg_hw_dev_specs_init(priv);
380	if (ret)
381		return ret;
382
383	hbg_reg_write_field(priv, HBG_REG_BUS_CTRL_ADDR,
384			    HBG_REG_BUS_CTRL_ENDIAN_M,
385			    HBG_ENDIAN_CTRL_LE_DATA_BE);
386	hbg_reg_write_field(priv, HBG_REG_MODE_CHANGE_EN_ADDR,
387			    HBG_REG_MODE_CHANGE_EN_B, HBG_STATUS_ENABLE);
388
389	hbg_hw_init_rx_control(priv);
390	hbg_hw_init_transmit_ctrl(priv);
391
392	hbg_hw_set_fifo_thrsld(priv, HBG_FIFO_TX_FULL_THRSLD,
393			       HBG_FIFO_TX_EMPTY_THRSLD, HBG_DIR_TX);
394	hbg_hw_set_fifo_thrsld(priv, HBG_FIFO_RX_FULL_THRSLD,
395			       HBG_FIFO_RX_EMPTY_THRSLD, HBG_DIR_RX);
396	hbg_hw_set_cfg_fifo_thrsld(priv, HBG_CFG_FIFO_FULL_THRSLD,
397				   HBG_CFG_FIFO_EMPTY_THRSLD, HBG_DIR_TX_RX);
398	return 0;
399}
~/ Read-only file preview.