drivers/net/dsa/qca/qca8k-8xxx.c

Source file repositories/reference/linux-study-clean/drivers/net/dsa/qca/qca8k-8xxx.c

File Facts

System
Linux kernel
Corpus path
drivers/net/dsa/qca/qca8k-8xxx.c
Extension
.c
Size
56421 bytes
Lines
2238
Domain
Driver Families
Bucket
drivers/net
Inferred role
Driver Families: implementation source
Status
source implementation candidate

Why This File Exists

Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.

Dependency Surface

Detected Declarations

Annotated Snippet

if (len > QCA_HDR_MGMT_DATA1_LEN) {
			__le32 *data2 = (__le32 *)skb->data;
			int data_len = min_t(int, QCA_HDR_MGMT_DATA2_LEN,
					     len - QCA_HDR_MGMT_DATA1_LEN);

			val++;

			for (i = sizeof(u32); i <= data_len; i += sizeof(u32)) {
				*val = get_unaligned_le32(data2);
				val++;
				data2++;
			}
		}
	}

	complete(&mgmt_eth_data->rw_done);
}

static struct sk_buff *qca8k_alloc_mdio_header(enum mdio_cmd cmd, u32 reg, u32 *val,
					       int priority, unsigned int len)
{
	struct qca_mgmt_ethhdr *mgmt_ethhdr;
	unsigned int real_len;
	struct sk_buff *skb;
	__le32 *data2;
	u32 command;
	u16 hdr;
	int i;

	skb = dev_alloc_skb(QCA_HDR_MGMT_PKT_LEN);
	if (!skb)
		return NULL;

	/* Hdr mgmt length value is in step of word size.
	 * As an example to process 4 byte of data the correct length to set is 2.
	 * To process 8 byte 4, 12 byte 6, 16 byte 8...
	 *
	 * Odd values will always return the next size on the ack packet.
	 * (length of 3 (6 byte) will always return 8 bytes of data)
	 *
	 * This means that a value of 15 (0xf) actually means reading/writing 32 bytes
	 * of data.
	 *
	 * To correctly calculate the length we devide the requested len by word and
	 * round up.
	 * On the ack function we can skip the odd check as we already handle the
	 * case here.
	 */
	real_len = DIV_ROUND_UP(len, sizeof(u16));

	/* We check if the result len is odd and we round up another time to
	 * the next size. (length of 3 will be increased to 4 as switch will always
	 * return 8 bytes)
	 */
	if (real_len % sizeof(u16) != 0)
		real_len++;

	/* Max reg value is 0xf(15) but switch will always return the next size (32 byte) */
	if (real_len == 16)
		real_len--;

	skb_reset_mac_header(skb);
	skb_set_network_header(skb, skb->len);

	mgmt_ethhdr = skb_push(skb, QCA_HDR_MGMT_HEADER_LEN + QCA_HDR_LEN);

	hdr = FIELD_PREP(QCA_HDR_XMIT_VERSION, QCA_HDR_VERSION);
	hdr |= FIELD_PREP(QCA_HDR_XMIT_PRIORITY, priority);
	hdr |= QCA_HDR_XMIT_FROM_CPU;
	hdr |= FIELD_PREP(QCA_HDR_XMIT_DP_BIT, BIT(0));
	hdr |= FIELD_PREP(QCA_HDR_XMIT_CONTROL, QCA_HDR_XMIT_TYPE_RW_REG);

	command = FIELD_PREP(QCA_HDR_MGMT_ADDR, reg);
	command |= FIELD_PREP(QCA_HDR_MGMT_LENGTH, real_len);
	command |= FIELD_PREP(QCA_HDR_MGMT_CMD, cmd);
	command |= FIELD_PREP(QCA_HDR_MGMT_CHECK_CODE,
					   QCA_HDR_MGMT_CHECK_CODE_VAL);

	put_unaligned_le32(command, &mgmt_ethhdr->command);

	if (cmd == MDIO_WRITE)
		put_unaligned_le32(*val, &mgmt_ethhdr->mdio_data);

	mgmt_ethhdr->hdr = htons(hdr);

	data2 = skb_put_zero(skb, QCA_HDR_MGMT_DATA2_LEN + QCA_HDR_MGMT_PADDING_LEN);
	if (cmd == MDIO_WRITE && len > QCA_HDR_MGMT_DATA1_LEN) {
		int data_len = min_t(int, QCA_HDR_MGMT_DATA2_LEN,
				     len - QCA_HDR_MGMT_DATA1_LEN);

Annotation

Implementation Notes